Skip to course content
Free FastAPI backend course

FastAPI for AI Backend Development

Unit 07.03: Overriding a dependency in a test

Overriding a dependency is what lets the whole request path run without the expensive part.

The same code path, a different implementation

An endpoint depending on a model, with the dependency replaced.

The code calls it before and after the override.

from fastapi import Depends, FastAPI
from fastapi.testclient import TestClient


def get_model():
    return {"name": "real-model", "cost": "money"}


app = FastAPI()


@app.get("/predict")
def predict(model=Depends(get_model)) -> dict:
    return {"used": model["name"]}


client = TestClient(app)
print("without override:", client.get("/predict").json())

app.dependency_overrides[get_model] = lambda: {"name": "fake-model", "cost": "none"}
print("with override   :", client.get("/predict").json())
app.dependency_overrides.clear()

print("""
`dependency_overrides` is the reason to inject the model rather than import
it. The whole request path -- routing, validation, response model, error
handling -- runs, with no network call and no cost.
""")

Routing, validation, the response model and error handling all ran. The only thing replaced was the part that costs money and needs a network.

This is the payoff for the injection in the previous units. An imported module-level client cannot be replaced this way, which is why the structural decision comes first and the testing benefit follows.

The mistake this prevents

The mistake is patching the module's attributes in tests to achieve the same thing. It works and it depends on import order and internal names, so it breaks on refactors that changed nothing about behaviour.

Takeaway

dependency_overrides replaces the expensive dependency while the whole request path still runs. It is the reason to inject rather than import.