FastAPI dependency override: unit-тест с подменой зависимостей через Pytest
Пример, как в Pytest заменить get_db на тестовый фейк через app.dependency_overrides. Локальный SQLite и чистый rollback — никаких моков.
**Как это работает**
dependency_overrides динамически подменяет «боевой» get_db на in-memory SQLite: тесты становятся изолированными, выполняются быстро и не требуют мокать ORM-методы. После каждого теста rollback() возвращает БД в чистое состояние — идеальный вариант для CI без Docker.
# app/deps.py
def get_db():
db = create_session() # рабочая БД (PostgreSQL, MySQL…)
try:
yield db
finally:
db.close()
# tests/conftest.py
import pytest, asyncio, sqlalchemy as sa
from httpx import AsyncClient
from app.main import app
from app import deps
TEST_DB_URL = "sqlite+aiosqlite:///:memory:"
engine = sa.create_async_engine(TEST_DB_URL, echo=False)
async_session = sa.orm.sessionmaker(engine, class_=sa.ext.asyncio.AsyncSession)
async def override_db():
async with async_session() as s: # ⚡️ тестовая БД в памяти
yield s
await s.rollback() # чистим изменения
@pytest.fixture(autouse=True, scope="session")
def setup_override():
app.dependency_overrides[deps.get_db] = override_db
yield
app.dependency_overrides.clear()
@pytest.fixture
async def client():
async with AsyncClient(app=app, base_url="http://test") as ac:
yield ac
# tests/test_users.py
async def test_create_user(client):
resp = await client.post("/users", json={"email": "a@b.c", "password": "123"})
assert resp.status_code == 201