Testing Web APIs
API tests hit your application in-process without starting a server. FastAPI's TestClient, Flask's test client, and Django's Client send requests and assert on responses.
Search across all documentation pages
API tests hit your application in-process without starting a server. FastAPI's TestClient, Flask's test client, and Django's Client send requests and assert on responses.
from fastapi.testclient import TestClient
from myapp.main import app
client = TestClient(app)
def test_health():
response = client.get("/health")
assert response.status_code == 200
assert response.json() == {"status": "ok"}When to reach for this:
# tests/conftest.py
import pytest
from fastapi.testclient import TestClient
from myapp.main import app
@pytest.fixture
def client():
return TestClient(app)
@pytest.fixture
def auth_client(client):
client.headers.update({"Authorization": "Bearer test-token"})
return clientdef test_create_invoice(client):
response = client.post("/invoices", json={"amount": 100.0, "currency": "USD"})
assert response.status_code == 201
data = response.json()
assert data["amount"] == 100.0
assert "id" in data
def test_unauthorized(auth_client):
response = auth_client.get("/admin/users")
assert response.status_code in (200, 403)
def test_validation_error(client):
response = client.post("/invoices", json={"amount": -1})
assert response.status_code == 422What this demonstrates:
TestClient runs the ASGI app in-process.json()| Framework | Client | Import |
|---|---|---|
| FastAPI | TestClient | fastapi.testclient |
| Flask | test_client() | app.test_client() |
| Django | Client | django.test.Client |
| Any ASGI | httpx + transport | httpx.ASGITransport |
import httpx
from httpx import ASGITransport
@pytest.fixture
async def async_client():
transport = ASGITransport(app=app)
async with httpx.AsyncClient(transport=transport, base_url="http://test") as c:
yield cwith TestClient(app) as client: context manager.| Alternative | Use When | Don't Use When |
|---|---|---|
| httpx against running server | E2E staging tests | Unit/route tests |
| Schemathesis | OpenAPI fuzzing | Simple CRUD routes |
| Postman/Newman | Manual exploration | Automated CI unit tests |
TestClient for sync tests (simpler). httpx AsyncClient for async test suites.
app.dependency_overrides[dep] = lambda: mock_value in fixture setup/teardown.
client = app.test_client() then client.get("/path").
pytest-django + client.get("/url/") with Django test Client.
No. In-process clients are faster and deterministic.
TestClient(app).websocket_connect("/ws") for FastAPI/Starlette.
client.post("/upload", files={"file": ("test.txt", b"content")}).
Send requests that trigger middleware. Assert headers and status changes.
Integration tests: yes (test DB). Unit route tests: override with mock or SQLite.
Assert /openapi.json structure or use Schemathesis for property-based API testing.
Stack versions: This page was written for Python 3.14.0, FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, and uv 0.6+.
Reviewed by Chris St. John·Last updated Jul 19, 2026