Dependency Overrides for Testing
Introduction
FastAPI lets you replace any dependency with a test double via app.dependency_overrides. The override applies only to your tests, leaves your application code untouched, and disappears when you clear it.
Why This Matters
Tests should run fast, repeatable, and without depending on real databases, external services, or live credentials. Dependency overrides let you swap the real dependency for an in-memory, deterministic fake without changing route code or introducing test-only if branches.
How Overrides Work
app.dependency_overrides is a dictionary that maps the original dependency callable to a replacement callable. When FastAPI sees a Depends(original) and original is in the dictionary, it calls the replacement instead.
from fastapi import FastAPI, Depends
from fastapi.testclient import TestClient
app = FastAPI()
def get_settings():
return {"env": "production", "debug": False}
@app.get("/config")
def config(settings: dict = Depends(get_settings)):
return settings
def fake_settings():
return {"env": "test", "debug": True}
app.dependency_overrides[get_settings] = fake_settings
client = TestClient(app)
response = client.get("/config")
assert response.json() == {"env": "test", "debug": True}The route did not change. Only the dependency target was swapped.
Using Overrides in pytest
In a real test suite, set the override in a fixture so each test gets a clean state:
import pytest
from fastapi.testclient import TestClient
from myapp.main import app, get_settings
@pytest.fixture
def client():
def fake_settings():
return {"env": "test", "debug": True}
app.dependency_overrides[get_settings] = fake_settings
yield TestClient(app)
app.dependency_overrides.clear()The yield lets the test run with the override; the cleanup runs afterward, no matter how the test ends.
Overriding a Database Dependency
The most common use case is swapping a real database for an in-memory one:
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, Session
from myapp.main import app, get_db
test_engine = create_engine("sqlite:///:memory:")
TestSessionLocal = sessionmaker(bind=test_engine)
def override_get_db():
db = TestSessionLocal()
try:
yield db
finally:
db.close()
@pytest.fixture
def client():
app.dependency_overrides[get_db] = override_get_db
yield TestClient(app)
app.dependency_overrides.clear()Tests run against an in-memory SQLite database, isolated and fast.
Overriding the Current User
Authentication is another typical override target:
from myapp.auth import get_current_user
from myapp.models import User
def fake_admin_user():
return User(id=1, username="admin", is_admin=True)
@pytest.fixture
def admin_client():
app.dependency_overrides[get_current_user] = fake_admin_user
yield TestClient(app)
app.dependency_overrides.clear()You can write tests against admin-only routes without dealing with login flows.
Different Overrides per Test
Set the override inside the test itself when behavior varies:
def test_unauthorized_user_is_rejected():
def fake_unauth():
raise HTTPException(status_code=401, detail="Not authenticated")
app.dependency_overrides[get_current_user] = fake_unauth
client = TestClient(app)
response = client.get("/me")
assert response.status_code == 401
app.dependency_overrides.clear()For more complex scenarios, parametrize the fixture so the override is configured by the test.
Overriding Sub-Dependencies
You can override any dependency in the chain, not just top-level ones:
def get_token() -> str:
return "real-token"
def get_user(token: str = Depends(get_token)) -> str:
return f"user-from-{token}"
# Override only the inner dependency
app.dependency_overrides[get_token] = lambda: "test-token"The downstream get_user runs unchanged but receives the fake token.
Clearing Overrides
Always clear overrides between tests. The cleanest pattern is fixture-scoped:
@pytest.fixture(autouse=True)
def clean_overrides():
yield
app.dependency_overrides.clear()autouse=True runs the fixture for every test automatically, preventing one test's override from leaking into another.
Common Mistakes
Not clearing overrides between tests
A leftover override silently changes the behavior of unrelated tests. Always clear it, ideally in a fixture.
Putting test logic inside production code
If you find yourself writing if testing: ... in a dependency, the right answer is an override, not a flag.
Overriding too late
Set the override before the request runs. Inside an async test, that means before calling the client.
Summary
app.dependency_overrides swaps any dependency with a replacement, scoped to your tests. Use it for databases, authentication, configuration, and any external client. Clear the overrides between tests, and your suite stays fast, deterministic, and free of test-only branches in production code.
How is this guide?
Last updated on
