FastAPI Testing (pytest + httpx)
Test FastAPI apps with pytest, httpx AsyncClient, and isolated DB fixtures.
# CLAUDE.md — FastAPI Testing (pytest + httpx)
## Stack
- **pytest** + **pytest-asyncio** + **httpx**.
- Use `httpx.AsyncClient` with the FastAPI app as transport — not the legacy `TestClient` synchronously, unless you have purely sync code.
- `anyio` is fine too if you prefer the trio-compatible style.
## Async client fixture
```python
@pytest.fixture
async def client(app) -> AsyncIterator[AsyncClient]:
async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as c:
yield c
```
- Use `ASGITransport` so the request never touches a real socket.
- Keep `base_url` consistent so logs are readable.
## Database isolation
- Spin up a Postgres container for tests (Docker Compose, Testcontainers, or a local `pg_tmp`). SQLite isn't equivalent.
- Each test runs in a transaction that rolls back at the end:
```python
@pytest.fixture
async def db(engine):
async with engine.connect() as conn:
trans = await conn.begin()
session = AsyncSession(bind=conn, expire_on_commit=False)
yield session
await session.close()
await trans.rollback()
```
- Override `get_db` via `app.dependency_overrides` so the endpoint uses the test session.
## Factories
- **factory_boy** with async-friendly post-generation hooks, or just plain async factory functions.
- Factories return persisted objects unless you ask for `build`-only.
- Don't share factory state across tests — every test creates what it needs.
## Auth in tests
- Override `get_current_user` to return a test user. Don't hit the real JWT issue endpoint in every test.
- Have a separate test category that *does* exercise the real auth flow — keep it small and slow.
## What to test
- **Endpoint contract**: status codes, response shape, validation errors. Use Pydantic schemas to assert on shape.
- **Side effects**: row was created, email task was enqueued, cache was invalidated.
- **Edge cases**: missing fields, unauthorized users, conflicting state.
## Speed
- `--reuse-db` equivalent: reuse the test DB across runs by skipping migrations on every test.
- `pytest -n auto` with `pytest-xdist` parallelism. Make sure factories don't collide on unique constraints.
- Profile with `pytest --durations=10`. Fix the worst offenders before they multiply.
## Don't
- Don't make HTTP calls to a running dev server in tests. Use the app directly via ASGI.
- Don't mock `httpx.AsyncClient` — test against the real client with a stubbed transport when calling external services.
- Don't rely on insertion order. Use deterministic ordering in queries when asserting.
- Don't share authenticated user state across tests via session middleware.
Other FastAPI templates
FastAPI + Pydantic + SQLAlchemy
Standard FastAPI stack: Pydantic v2, SQLAlchemy 2.0, dependency injection.
FastAPI Async + Postgres
Async-first FastAPI with asyncpg, connection pooling, and migrations.
FastAPI JWT Authentication
JWT auth with refresh tokens, password hashing, and role-based access.
FastAPI Production Deploy
Docker images, uvicorn workers, Kubernetes manifests, observability.