In a more complicated setup using the python dependency injector framework I use the lifespan function for the FastAPI app object to correctly wire everything.
When testing I'd like to replace some of the objects with different versions (fakes), and the natural way to accomplish that seems to me like I should override or mock the lifespan function of the app object. However I can't seem to figure out if/how I can do that.
MRE follows
import pytest
from contextlib import asynccontextmanager
from fastapi.testclient import TestClient
from fastapi import FastAPI, Response, status
greeting = None
@asynccontextmanager
async def _lifespan(app: FastAPI):
# Initialize dependency injection
global greeting
greeting = "Hello"
yield
@asynccontextmanager
async def _lifespan_override(app: FastAPI):
# Initialize dependency injection
global greeting
greeting = "Hi"
yield
app = FastAPI(title="Test", lifespan=_lifespan)
@app.get("/")
async def root():
return Response(status_code=status.HTTP_200_OK, content=greeting)
@pytest.fixture
def fake_client():
with TestClient(app) as client:
yield client
def test_override(fake_client):
response = fake_client.get("/")
assert response.text == "Hi"
So basically in the fake_client fixture I'd like to change it to use the _lifespan_override instead of the original _lifespan, making the dummy test-case above pass
I'd have expected something like with TestClient(app, lifespan=_lifespan_override) as client: to work, but that's not supported. Is there some way I can mock it to get the behavior I want?
(The mre above works if you replace "Hi" with "Hello" in the assert statement)
pyproject.toml below with needed dependencies
[tool.poetry]
name = "mre"
version = "0.1.0"
description = "mre"
authors = []
[tool.poetry.dependencies]
python = "^3.10"
fastapi = "^0.103.2"
[tool.poetry.group.dev.dependencies]
pytest = "^7.1.2"
httpx = "^0.25.0"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
EDIT: Tried extending my code with the suggestion from Hamed Akhavan below as follows
@pytest.fixture
def fake_client():
app.dependency_overrides[_lifespan] = _lifespan_override
with TestClient(app) as client:
yield client
but it doesn't work, even though it looks like it should be the right approach. Syntax problem?