4.2 KiB
Async Testler
Sağlanan TestClient ile FastAPI uygulamalarınızı nasıl test edeceğinizi zaten gördünüz. Şimdiye kadar yalnızca senkron testler yazdık, yani async fonksiyonlar kullanmadan.
Testlerinizde asenkron fonksiyonlar kullanabilmek faydalı olabilir; örneğin veritabanınızı asenkron olarak sorguluyorsanız. Diyelim ki FastAPI uygulamanıza request gönderilmesini test etmek ve ardından async bir veritabanı kütüphanesi kullanırken backend'in doğru veriyi veritabanına başarıyla yazdığını doğrulamak istiyorsunuz.
Bunu nasıl çalıştırabileceğimize bir bakalım.
pytest.mark.anyio
Testlerimizde asenkron fonksiyonlar çağırmak istiyorsak, test fonksiyonlarımızın da asenkron olması gerekir. AnyIO bunun için güzel bir plugin sağlar; böylece bazı test fonksiyonlarının asenkron olarak çağrılacağını belirtebiliriz.
HTTPX
FastAPI uygulamanız async def yerine normal def fonksiyonları kullanıyor olsa bile, altta yatan yapı hâlâ bir async uygulamadır.
TestClient, standart pytest kullanarak normal def test fonksiyonlarınızın içinden asenkron FastAPI uygulamasını çağırmak için içeride bazı “sihirli” işlemler yapar. Ancak bu sihir, onu asenkron fonksiyonların içinde kullandığımızda artık çalışmaz. Testlerimizi asenkron çalıştırdığımızda, test fonksiyonlarımızın içinde TestClient kullanamayız.
TestClient, HTTPX tabanlıdır ve neyse ki API'yi test etmek için HTTPX'i doğrudan kullanabiliriz.
Örnek
Basit bir örnek için, Daha Büyük Uygulamalar ve Test Etme bölümlerinde anlatılana benzer bir dosya yapısı düşünelim:
.
├── app
│ ├── __init__.py
│ ├── main.py
│ └── test_main.py
main.py dosyası şöyle olur:
{* ../../docs_src/async_tests/app_a_py310/main.py *}
test_main.py dosyasında main.py için testler yer alır, artık şöyle görünebilir:
{* ../../docs_src/async_tests/app_a_py310/test_main.py *}
Çalıştırma
Testlerinizi her zamanki gibi şu şekilde çalıştırabilirsiniz:
$ pytest
---> 100%
Detaylı Anlatım
@pytest.mark.anyio marker'ı, pytest'e bu test fonksiyonunun asenkron olarak çağrılması gerektiğini söyler:
{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[7] *}
/// tip | İpucu
Test fonksiyonu artık TestClient kullanırken eskiden olduğu gibi sadece def değil, async def.
///
Ardından app ile bir AsyncClient oluşturup await kullanarak ona async request'ler gönderebiliriz.
{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[9:12] *}
Bu, şu kullanıma denktir:
response = client.get('/')
...ki daha önce request'leri TestClient ile bu şekilde gönderiyorduk.
/// tip | İpucu
Yeni AsyncClient ile async/await kullandığımızı unutmayın; request asenkron çalışır.
///
/// warning | Uyarı
Uygulamanız lifespan event'lerine dayanıyorsa, AsyncClient bu event'leri tetiklemez. Tetiklendiklerinden emin olmak için florimondmanca/asgi-lifespan paketindeki LifespanManager'ı kullanın.
///
Diğer Asenkron Fonksiyon Çağrıları
Test fonksiyonu artık asenkron olduğundan, testlerinizde FastAPI uygulamanıza request göndermenin yanında başka async fonksiyonları da (çağırıp await ederek) kodunuzun başka yerlerinde yaptığınız gibi aynı şekilde kullanabilirsiniz.
/// tip | İpucu
Testlerinize asenkron fonksiyon çağrıları entegre ederken RuntimeError: Task attached to a different loop hatasıyla karşılaşırsanız (ör. MongoDB'nin MotorClient kullanımı), event loop gerektiren nesneleri yalnızca async fonksiyonların içinde oluşturmanız gerektiğini unutmayın; örneğin bir @app.on_event("startup") callback'i içinde.
///