Day 14 · ~12m

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.

Already have an account? Sign in