All FastAPI templates

FastAPI Testing (pytest + httpx)

Test FastAPI apps with pytest, httpx AsyncClient, and isolated DB fixtures.

DevZone Tools1,140 copiesUpdated Mar 25, 2026FastAPIPython
# 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