Testing with a database helps make sure your app works well when saving or reading data. It checks if your database code is correct and reliable.
Testing with database in FastAPI
from fastapi.testclient import TestClient from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from myapp.main import app, get_db from myapp.database import Base # Create a test database engine SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db" engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}) TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) # Override the get_db dependency to use test DB def override_get_db(): db = TestingSessionLocal() try: yield db finally: db.close() app.dependency_overrides[get_db] = override_get_db client = TestClient(app)
Use a separate test database to avoid messing with real data.
Override the database dependency in FastAPI to use the test database during tests.
def test_create_item(): response = client.post("/items/", json={"name": "Test Item"}) assert response.status_code == 200 assert response.json()["name"] == "Test Item"
def test_read_items(): response = client.get("/items/") assert response.status_code == 200 assert isinstance(response.json(), list)
This example shows a FastAPI app with a simple Item model and a POST endpoint to create items. It sets up a separate test database and overrides the database dependency for testing. The test sends a request to create an item and checks the response.
from fastapi import FastAPI, Depends from fastapi.testclient import TestClient from sqlalchemy import create_engine, Column, Integer, String from sqlalchemy.orm import sessionmaker, declarative_base, Session SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db" engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}) SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) Base = declarative_base() class Item(Base): __tablename__ = "items" id = Column(Integer, primary_key=True, index=True) name = Column(String, index=True) Base.metadata.create_all(bind=engine) app = FastAPI() def get_db(): db = SessionLocal() try: yield db finally: db.close() @app.post("/items/") def create_item(name: str, db: Session = Depends(get_db)): item = Item(name=name) db.add(item) db.commit() db.refresh(item) return {"id": item.id, "name": item.name} # Testing setup SQLALCHEMY_TEST_DATABASE_URL = "sqlite:///./test_test.db" test_engine = create_engine(SQLALCHEMY_TEST_DATABASE_URL, connect_args={"check_same_thread": False}) TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=test_engine) Base.metadata.create_all(bind=test_engine) def override_get_db(): db = TestingSessionLocal() try: yield db finally: db.close() app.dependency_overrides[get_db] = override_get_db client = TestClient(app) def test_create_item(): response = client.post("/items/", json={"name": "Test Item"}) assert response.status_code == 200 data = response.json() assert data["name"] == "Test Item" assert "id" in data if __name__ == "__main__": test_create_item() print("Test passed")
Always use a separate database for tests to keep your real data safe.
Use FastAPI's dependency override feature to swap the database during tests.
Run tests often to catch bugs early.
Testing with a database helps verify your app's data handling.
Use a separate test database and override dependencies in FastAPI.
Write simple tests to check creating and reading data.
Practice
Solution
Step 1: Understand test isolation
Tests should not affect real data to avoid accidental data loss or corruption.Step 2: Use separate test database
Using a separate database keeps test data separate and allows safe repeated testing.Final Answer:
To avoid changing real data and keep tests isolated -> Option CQuick Check:
Separate test database = safe isolated tests [OK]
- Using production database for tests
- Not cleaning test data after tests
- Assuming tests don't affect real data
Solution
Step 1: Recall FastAPI dependency override syntax
FastAPI uses the dictionary app.dependency_overrides to replace dependencies during tests.Step 2: Match correct syntax
Assigning override_get_db function to app.dependency_overrides[get_db] is the correct method.Final Answer:
app.dependency_overrides[get_db] = override_get_db -> Option DQuick Check:
Override dependencies via app.dependency_overrides dict [OK]
- Using non-existent methods like set_dependency
- Trying to override dependencies without assignment
- Confusing syntax with other frameworks
response.json()?
def test_create_item(client):
response = client.post('/items/', json={'name': 'Book', 'price': 10})
return response.json()Solution
Step 1: Understand POST /items/ behavior
Assuming the endpoint creates an item and returns it with an assigned id.Step 2: Analyze response.json()
The response should include the new item's id plus the sent data.Final Answer:
{'id': 1, 'name': 'Book', 'price': 10} -> Option AQuick Check:
POST creates item and returns it with id [OK]
- Expecting only sent data without id
- Assuming POST is disallowed
- Ignoring response content
def override_get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
app.dependency_overrides[get_db] = override_get_db
def test_read_items(client):
response = client.get('/items/')
assert response.status_code == 200
assert response.json() == []Solution
Step 1: Check override_get_db function
It uses SessionLocal but does not ensure a separate test database or transaction rollback.Step 2: Identify test isolation problem
Without a test database or rollback, tests may affect real data or each other.Final Answer:
The test database session is not properly created or isolated -> Option BQuick Check:
Test DB session must be isolated and separate [OK]
- Not using a test database
- Not overriding dependencies correctly
- Assuming client is auto-defined
Solution
Step 1: Use separate test database URL
This prevents tests from affecting production data.Step 2: Override get_db to yield test session and rollback
This ensures each test runs isolated and cleans up changes automatically.Final Answer:
Use a test database URL, override get_db to yield a session from it, and rollback after each test -> Option AQuick Check:
Separate DB + override + rollback = clean isolated tests [OK]
- Using production DB for tests
- Not cleaning test data after tests
- Skipping dependency overrides
Ready to prove it?
Pass the test and this pattern moves unknown
