Skip to course content
Free FastAPI backend course

FastAPI for AI Backend Development

Unit 09.00: Testing the whole request path in-process

TestClient exercises the whole request path in-process, with no server and no network.

Everything except the network

Routing, validation, dependency resolution, the handler, the response model and error handling - all in a function call.

The code posts a valid and an invalid request.

from fastapi import FastAPI
from fastapi.testclient import TestClient
from pydantic import BaseModel, Field

app = FastAPI()


class Request(BaseModel):
    text: str = Field(min_length=1, max_length=40)


@app.post("/classify")
def classify(body: Request) -> dict:
    return {"category": "billing", "confidence": 0.9}


client = TestClient(app)
r = client.post("/classify", json={"text": "charged twice"})
print(f"status {r.status_code}, body {r.json()}")
print(f"invalid -> {client.post('/classify', json={'text': ''}).status_code}")

print("""
`TestClient` runs routing, validation, dependency resolution, the handler, the
response model and error handling -- in-process, with no server, no port and
no network.

That is most of what breaks in an API, exercised in milliseconds.
""")

That covers most of what actually breaks in an API. Validation rules, status codes, response filtering and dependency wiring are all exercised, in milliseconds.

There is no port to bind, nothing to start and nothing to tear down, which is what makes it fast enough to run on every save.

The mistake this prevents

The mistake is testing by starting the server and calling it with an HTTP client. It is slower, it needs a free port, it fails in CI for reasons unrelated to your code, and it tests nothing extra.

Takeaway

TestClient runs the full request path in-process. It covers routing, validation, dependencies, response models and error handling without a network.