Testing with httpx
FastAPI интегрируется с starlette.testclient.TestClient, который под капотом
— синхронный httpx. Для настоящих async-тестов есть httpx.AsyncClient +
ASGITransport.
Базовый тест
from fastapi.testclient import TestClient
from app.main import app
client = TestClient(app)
def test_root():
r = client.get("/")
assert r.status_code == 200
assert r.json() == {"message": "hello"}Override зависимостей
Не поднимать настоящую БД ради тестов — подменить через dependency_overrides:
from app.deps import get_db
from app.main import app
def fake_db():
return FakeSession()
app.dependency_overrides[get_db] = fake_db
def test_items():
r = client.get("/items")
assert r.status_code == 200app.dependency_overrides — глобальный dict; чистить в фикстуре с yield.
Async-тесты
TestClient сам гоняет async через anyio. Если нужен реальный async-context
(например, проверка BackgroundTasks):
import httpx
import pytest
@pytest.mark.anyio
async def test_async():
transport = httpx.ASGITransport(app=app)
async with httpx.AsyncClient(transport=transport, base_url="http://test") as ac:
r = await ac.get("/")
assert r.status_code == 200Фикстуры pytest
import pytest
from fastapi.testclient import TestClient
from app.main import app
from app.deps import get_db
@pytest.fixture
def client():
app.dependency_overrides[get_db] = lambda: FakeSession()
with TestClient(app) as c:
yield c
app.dependency_overrides.clear()
def test_signup(client):
r = client.post("/signup", json={"email": "a@b.c"})
assert r.status_code == 200Покрытие
- 200/4xx/5xx для каждого эндпоинта хотя бы по одному
- Валидация 422 на невалидных payload
- Кастомные валидаторы — отдельный тест на каждый raise
- Override зависимостей в каждом тесте, чтобы тесты не лезли в реальные ресурсы
Чеклист
- Каждый эндпоинт покрыт хотя бы happy-path тестом
- Невалидные payload → 422, не 500
- БД и внешние API подменены через
dependency_overrides -
app.dependency_overrides.clear()после каждого теста - Тесты запускаются быстро (<1с на тест) — иначе никто не будет их гонять
Связанные заметки
- Dependency Injection — что именно подменяем
- Async & Background Tasks — что тестировать в async-эндпоинтах