codejump

Test FastAPI through HTTP

Exercise real request parsing and responses with TestClient, replace dependencies, and handle lifespan in async tests.

1 min readUpdated

3 exercises

Waiting at the end of this page.

Key takeaways

  • Send requests to the app in tests so routing, validation, dependencies, and response models all run.
  • Override external resources with test dependencies and clear overrides after each test.
  • Use a TestClient context manager for lifespan events; HTTPX ASGITransport does not trigger them on its own.

Test the HTTP contract

FastAPI's TestClient makes an in-process request to the app. Assert both the status and the response body, including error cases:

python
from fastapi.testclient import TestClient
from app import app

def test_missing_book():
    with TestClient(app) as client:
        response = client.get("/books/999")
    assert response.status_code == 404
    assert response.json() == {"detail": "Book not found"}

The context manager runs application lifespan startup and shutdown. That matters when startup creates tables or loads resources. Calling the route function directly would skip parsing, validation, dependencies, exception handling, and serialization.

Replace slow or external resources

If a route depends on get_db, override that callable with a test database provider. The route still runs through FastAPI, but it uses isolated test data:

python
app.dependency_overrides[get_db] = get_test_db
try:
    with TestClient(app) as client:
        response = client.get("/books/1")
    assert response.status_code == 200
finally:
    app.dependency_overrides.clear()

In a full test suite, put setup and cleanup in a fixture. A mutable override map left behind can make later tests pass or fail depending on order. A fresh database or transaction per test keeps data isolated too.

Async tests and lifespan

For an async test, HTTPX can send requests through ASGITransport(app=app) with AsyncClient. HTTPX does not start or stop the app's lifespan automatically, so enter lifespan separately when the app relies on it. Test a normal response, invalid input such as a 422, and important failure paths; the shape of detail is part of the client-facing contract.

Now practice it

3 exercises

Reading this page is the cheap half. These are the exercises that make you use it.