Testing FastAPI Apps with pytest

A
Author
06 Jul, 2026 1 min read 138 views

FastAPI apps are easy to test because endpoints are plain functions behind an ASGI app, and dependencies can be swapped per test.

A first test

# test_books.py
from fastapi.testclient import TestClient
from main import app

client = TestClient(app)

def test_create_and_get_book():
    res = client.post("/books", json={"title": "Dune", "author": "Frank Herbert"})
    assert res.status_code == 201
    book_id = res.json()["id"]

    res = client.get(f"/books/{book_id}")
    assert res.json()["title"] == "Dune"

def test_validation_error():
    res = client.post("/books", json={"title": "No author"})
    assert res.status_code == 422
pip install pytest
pytest -q

Overriding dependencies

import pytest
from main import app, get_current_user, get_db

@pytest.fixture
def client(test_db_session):
    app.dependency_overrides[get_db] = lambda: test_db_session
    app.dependency_overrides[get_current_user] = lambda: User(id=1, email="test@example.com", role="admin")
    with TestClient(app) as c:     # 'with' also runs lifespan startup/shutdown
        yield c
    app.dependency_overrides.clear()

def test_admin_can_delete(client):
    assert client.delete("/articles/1").status_code == 204

Async tests

import pytest
from httpx import ASGITransport, AsyncClient

@pytest.mark.anyio
async def test_list_posts():
    async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as ac:
        res = await ac.get("/posts")
    assert res.status_code == 200

A reliable test database

  • Run a real PostgreSQL in Docker or with Testcontainers for integration tests; SQLite behaves differently.
  • Wrap each test in a transaction and roll it back, so tests don't affect each other.
  • Use factory functions to create test data with sensible defaults.
Was this article helpful?

Comments

No comments yet. Have a question or a tip? Be the first to share it.

Leave a comment

Comments are reviewed before they appear.