Testing with an In-Memory Database
Exit

Testing with an In-Memory Database

Understand why tests need database isolation and how in-memory SQLite provides it

Why the current tests are broken

Your tests from Course 2 use a global client = TestClient(app) at the top of test_main.py. That client connects to the real app, which now uses SQLite. Two problems follow:

Tests share state. When test_create_expense creates an expense and test_list_expenses runs next, it sees the expense from the previous test. Tests that depend on a clean state fail unpredictably.

Tests write to the real database. Every expense created during a test run ends up in expenses.db. Running your tests fills your development database with fake data.

The fix: an in-memory database per test

SQLite supports in-memory databases: instead of a file path, you pass an empty URL ("sqlite://"). The database exists only in memory and disappears when the connection closes. Each test gets a completely fresh database.

engine = create_engine("sqlite://", connect_args={"check_same_thread": False})
SQLModel.metadata.create_all(engine)

Swapping the session with dependency_overrides

Your endpoints use SessionDep — FastAPI calls get_session() and injects the result. To swap in a test session, you override the dependency:

app.dependency_overrides[get_session] = get_session_override

get_session_override is a function that yields a session connected to the in-memory engine instead of the real database. FastAPI uses the override for every request made through the test client.

pytest fixtures

A pytest fixture is a function that sets up resources for tests and cleans up afterward. When a test function has a parameter with the same name as a fixture, pytest calls the fixture and passes the result in automatically.

You will define a fixture called client that:

  1. Creates an in-memory engine and builds the tables
  2. Overrides get_session with a function that yields sessions from that engine
  3. Yields a TestClient connected to the app
  4. Clears the dependency overrides after the test finishes

Every test that declares client as a parameter gets its own isolated database.

Next Chapter →