Skip to course content
Free FastAPI backend course

FastAPI for AI Backend Development

Unit 09.01: Fixtures that make a test readable

A fixture arranges the state a test needs and resets what the last test left.

Arrange, and isolate

A client factory that clears shared state, and a helper that creates a record.

The code shows the isolation between two clients.

from fastapi import FastAPI
from fastapi.testclient import TestClient
from pydantic import BaseModel

app = FastAPI()
STORE = {}


class Item(BaseModel):
    name: str


@app.post("/items", status_code=201)
def create(body: Item) -> dict:
    item_id = f"item-{len(STORE) + 1}"
    STORE[item_id] = body.name
    return {"id": item_id}


# In pytest these are fixtures; here they are plain functions doing the same job.
def make_client():
    STORE.clear()
    return TestClient(app)


def a_created_item(client):
    return client.post("/items", json={"name": "widget"}).json()["id"]


client = make_client()
item_id = a_created_item(client)
print(f"arranged: {item_id}, store size {len(STORE)}")

client = make_client()
print(f"fresh client: store size {len(STORE)}  <- isolation between tests")

# The fixture resets shared state. Without that, tests pass alone and fail in a
# suite, or worse pass in a suite and fail alone -- and the order dependency
# takes far longer to find than the original bug.

The reset is the important half. Without it, tests pass alone and fail in a suite - or worse, pass in a suite and fail alone, because one test depended on state another created.

That order dependency takes far longer to find than the original bug, because the failing test is rarely the one at fault.

The mistake this prevents

The mistake is sharing one client and one store across the whole suite because it is faster. The speed gained is trivial and the debugging cost when tests interact is not.

Takeaway

Reset shared state in the fixture. Tests that depend on each other's leftovers fail in ways that point at the wrong test.