Testing APIs
Write automated tests with TestClient and pytest for your FastAPI endpoints.
I've been testing my API by hitting it manually in the browser. Is there a better way?
Automated tests. FastAPI's TestClient lets you call endpoints in code without starting a server:
from fastapi.testclient import TestClient
from main import app
client = TestClient(app)
def test_root():
response = client.get("/")
assert response.status_code == 200
assert response.json() == {"message": "Hello, world"}
TestClient simulates HTTP requests. response.status_code gives you the HTTP status. response.json() parses the JSON body. assert checks your expectations — if any assertion fails, the test fails.
How do I test POST endpoints with request bodies?
Pass JSON data to client.post():
def test_create_task():
response = client.post("/tasks", json={
"title": "Test Task",
"priority": 3
})
assert response.status_code == 201
data = response.json()
assert data["title"] == "Test Task"
assert data["priority"] == 3
assert data["done"] == False
assert "id" in data
The json= parameter serializes your dict to JSON and sets the Content-Type header. Then you assert on the response.
What about testing error cases — like 404s and validation errors?
Those are just as important as success cases:
def test_task_not_found():
response = client.get("/tasks/99999")
assert response.status_code == 404
assert response.json()["detail"] == "Task not found"
def test_invalid_priority():
response = client.post("/tasks", json={
"title": "Bad",
"priority": 100
})
assert response.status_code == 422 # Validation error
Test the unhappy paths. If you only test success, you won't catch bugs in error handling.
How do I test endpoints that require authentication?
Pass headers to the test client:
def test_protected_endpoint():
# Without auth — should fail
response = client.get("/me")
assert response.status_code == 401
# With auth — should succeed
response = client.get("/me", headers={"X-API-Key": "key-123"})
assert response.status_code == 200
assert response.json()["user"] == "alice"
Every test should be independent. Don't rely on state from previous tests. If one test creates data, the next test shouldn't depend on it being there.
Run all tests with pytest -v — it discovers functions starting with test_ and runs them with detailed output.
Practice your skills
Sign up to write and run code in this lesson.
Testing APIs
Write automated tests with TestClient and pytest for your FastAPI endpoints.
I've been testing my API by hitting it manually in the browser. Is there a better way?
Automated tests. FastAPI's TestClient lets you call endpoints in code without starting a server:
from fastapi.testclient import TestClient
from main import app
client = TestClient(app)
def test_root():
response = client.get("/")
assert response.status_code == 200
assert response.json() == {"message": "Hello, world"}
TestClient simulates HTTP requests. response.status_code gives you the HTTP status. response.json() parses the JSON body. assert checks your expectations — if any assertion fails, the test fails.
How do I test POST endpoints with request bodies?
Pass JSON data to client.post():
def test_create_task():
response = client.post("/tasks", json={
"title": "Test Task",
"priority": 3
})
assert response.status_code == 201
data = response.json()
assert data["title"] == "Test Task"
assert data["priority"] == 3
assert data["done"] == False
assert "id" in data
The json= parameter serializes your dict to JSON and sets the Content-Type header. Then you assert on the response.
What about testing error cases — like 404s and validation errors?
Those are just as important as success cases:
def test_task_not_found():
response = client.get("/tasks/99999")
assert response.status_code == 404
assert response.json()["detail"] == "Task not found"
def test_invalid_priority():
response = client.post("/tasks", json={
"title": "Bad",
"priority": 100
})
assert response.status_code == 422 # Validation error
Test the unhappy paths. If you only test success, you won't catch bugs in error handling.
How do I test endpoints that require authentication?
Pass headers to the test client:
def test_protected_endpoint():
# Without auth — should fail
response = client.get("/me")
assert response.status_code == 401
# With auth — should succeed
response = client.get("/me", headers={"X-API-Key": "key-123"})
assert response.status_code == 200
assert response.json()["user"] == "alice"
Every test should be independent. Don't rely on state from previous tests. If one test creates data, the next test shouldn't depend on it being there.
Run all tests with pytest -v — it discovers functions starting with test_ and runs them with detailed output.
Practice your skills
Sign up to write and run code in this lesson.