When testing FastAPI applications with SQLModel, it is best practice to use pytest fixtures to manage the lifecycle of the database session and the TestClient.
By separating the setup into two distinct fixtures—one for the session and one for the client—you gain flexibility:
- The
session fixture: Manages the database connection and transaction lifecycle for the testing database. - The
client fixture: Provides a TestClient instance configured to use the testing database (often by overriding dependencies).
Key Pattern: Requiring Multiple Fixtures
If a test needs to both interact with the API via the client AND manipulate the database directly (e.g., to seed data before a request), you should require both the client and the session fixtures in your test function. Because fixtures can depend on other fixtures, the client fixture and your test function will share the same underlying session instance, ensuring data consistency during the test.
# Example pattern for a test requiring both client and session
def test_read_heroes(client: TestClient, session: Session):
# 1. Seed the database using the session fixture
hero_1 = Hero(name="Deadpool", secret_identity="Wade Wilson")
session.add(hero_1)
session.commit()
session.refresh(hero_1)
# 2. Use the client fixture to make the API request
response = client.get("/heroes/")
# 3. Assert the results
assert response.status_code == 200
assert response.json() == [{"id": hero_1.id, "name": "Deadpool", "secret_identity": "Wade Wilson"}]