Skip to main content

Testing & Debugging

Testing and debugging are critical for building reliable and maintainable FastAPI applications. This guide covers unit/integration testing, mocking, debugging, and automated API testing.

Testing FastAPI Apps with pytest​

pytest is the standard testing framework for Python. FastAPI works seamlessly with it.

Installation​

pip install pytest pytest-cov httpx

Basic Test Structure​

# tests/test_main.py
from fastapi.testclient import TestClient
from main import app

client = TestClient(app)

def test_read_root():
response = client.get("/")
assert response.status_code == 200
assert response.json() == {"message": "Hello World"}

Key Features:

  • TestClient – Simulates HTTP requests.
  • Assertions – Check status codes, response data, headers.
  • Fixtures – Reusable test setups (e.g., DB sessions).

Using TestClient (from fastapi.testclient)​

TestClient allows mocking HTTP requests without running a live server.

Example: Testing CRUD Endpoints​

def test_create_item():
response = client.post(
"/items/",
json={"name": "Foo", "price": 10.5},
)
assert response.status_code == 201
assert response.json() == {"name": "Foo", "price": 10.5}

def test_read_item():
response = client.get("/items/1")
assert response.status_code == 200
assert response.json() == {"id": 1, "name": "Foo"}

Supported Methods:

  • client.get()
  • client.post()
  • client.put()
  • client.delete()
  • client.options()

Mocking Dependencies for Testing​

Problem: Some dependencies (DB, external APIs) should not run in tests.

(A) Overriding Dependencies​

from fastapi import FastAPI, Depends
from main import app, get_db

# Override the real DB dependency
def mock_get_db():
return "Fake DB Session"

app.dependency_overrides[get_db] = mock_get_db

def test_with_mock_db():
response = client.get("/items/1")
assert response.json() == {"id": 1, "name": "Mocked Item"}

(B) Using unittest.mock​

from unittest.mock import patch

def test_external_api_call():
with patch("module.external_api") as mock_api:
mock_api.return_value = {"data": "mocked"}
response = client.get("/external-data")
assert response.json() == {"data": "mocked"}

Best Practices:

  • Mock external services (Stripe, SMTP).
  • Keep business logic unmocked.

Debugging with pdb, breakpoint(), and Logging​

(A) Debugging with pdb​

Insert a breakpoint in code:

import pdb; pdb.set_trace() # Python 3.7+

OR:

breakpoint() # Python 3.7+

Commands:

  • n (next line)
  • c (continue)
  • q (quit)

(B) Logging for Debugging​

import logging

logging.basicConfig(level=logging.DEBUG)

@app.get("/debug")
def debug_endpoint():
logging.debug("Debug message")
return {"status": "ok"}

Log Levels:

  • DEBUG (detailed info)
  • INFO (general logs)
  • ERROR (critical issues)

Automated API Testing (Postman, Swagger)​

(A) Postman/Newman​

  • Manual Testing: Use Postman GUI.

  • Automated Testing:

    newman run collection.json --environment env.json

    Workflow:

  1. Create a Postman Collection.
  2. Export as JSON.
  3. Run with newman in CI/CD.

(B) Swagger/OpenAPI Automated Tests​

FastAPI auto-generates OpenAPI docs (/docs). Tools like Schemathesis can test all endpoints:

pip install schemathesis
schemathesis run http://localhost:8000/openapi.json

Key Features:

  • Fuzz testing (malformed inputs).
  • Validate responses against OpenAPI schema.

Summary Table​

TaskTool/MethodKey Benefit
HTTP TestingTestClientSimulate API calls
Mockingdependency_overrides, unittest.mockIsolate tests
Debuggingpdb, breakpoint(), loggingFix issues faster
Automated TestingPostman, Newman, SchemathesisCI/CD integration

Best Practices​

  1. Test all status codes (200, 404, 422, etc.).
  2. Mock expensive calls (DB, APIs).
  3. Use pytest fixtures for reusable setups.
  4. Run tests in CI/CD (GitHub Actions, GitLab CI).
  5. Monitor test coverage (pytest --cov).