3 · Reliability and delivery · 45 MIN
Project · Test API behavior through HTTP
A useful API test checks the wire contract and failure responses.
TestClient calls the application through its HTTP interface without requiring a separately running server. These tests exercise Pydantic validation and the response model from the earlier preview lesson. They verify status codes and exact public fields, making accidental contract changes visible. Add dependency overrides when a route talks to external services, but keep at least some integration coverage for real database constraints in a disposable environment. Tests should never run destructive fixtures against a production database.
Keep the three contract tests passing.
Read the example
# test_main.py — use main.py from the FastAPI request-model lesson
from fastapi.testclient import TestClient
from main import app
client = TestClient(app)
def test_valid_preview():
response = client.post("/preview", json={"title": "Learn React", "weekly_goal": 3})
assert response.status_code == 200
assert response.json() == {"title": "Learn React", "weekly_goal": 3}
def test_invalid_goal():
assert client.post("/preview", json={"title": "React", "weekly_goal": 0}).status_code == 422
def test_unknown_field():
assert client.post("/preview", json={"title": "React", "weekly_goal": 3, "owner": "someone"}).status_code == 422Check the expected output
pytest reports three passing tests against the earlier preview application.
Your challenge
Build an authenticated plan service with separate create/list tests, then prove one account cannot read or modify another account’s plan.
Solution cost: Proportional to request validation and the tested dependency work. time · Bounded fixture and response data. space
Common trap
A validation test is not an authorization test; both failure classes need coverage.
Study the project implementation
# test_main.py — use main.py from the FastAPI request-model lesson
from fastapi.testclient import TestClient
from main import app
client = TestClient(app)
def test_valid_preview():
response = client.post("/preview", json={"title": "Learn React", "weekly_goal": 3})
assert response.status_code == 200
assert response.json() == {"title": "Learn React", "weekly_goal": 3}
def test_invalid_goal():
assert client.post("/preview", json={"title": "React", "weekly_goal": 0}).status_code == 422
def test_unknown_field():
assert client.post("/preview", json={"title": "React", "weekly_goal": 3, "owner": "someone"}).status_code == 422Further reading: Official documentation