如何在FastAPI TestClient中覆盖lifespan函数替换依赖对象?
解决FastAPI + Dependency Injector测试时替换Lifespan初始化对象的问题
为啥直接override lifespan不行?
FastAPI的app.dependency_overrides只能覆盖常规的依赖注入函数,lifespan是应用级的生命周期钩子,不属于这个体系,所以直接替换没用。
正确做法有两种,选适合你的:
方法一:重构lifespan,把初始化逻辑拆成可替换的依赖
把原来lifespan里的容器初始化逻辑抽成独立的依赖函数,这样就能用dependency_overrides替换了。
示例代码:
from fastapi import FastAPI, Depends from dependency_injector import containers, providers # 真实服务和假服务 class RealService: def get_data(self): return "real data" class FakeService: def get_data(self): return "fake data" # 定义容器 class Container(containers.DeclarativeContainer): service = providers.Singleton(RealService) # 把容器初始化做成依赖函数 def get_container(): container = Container() container.init_resources() yield container container.shutdown_resources() # 初始化应用,用这个依赖函数当lifespan app = FastAPI(lifespan=lambda _: get_container()) # 接口示例 @app.get("/") def read_root(container: Container = Depends(get_container)): return {"data": container.service().get_data()}
测试的时候,直接覆盖get_container:
from fastapi.testclient import TestClient def test_with_fake_service(): # 定义测试用的容器,替换服务为假实现 class TestContainer(Container): service = providers.Singleton(FakeService) # 测试用的容器初始化函数 def test_get_container(): container = TestContainer() container.init_resources() yield container container.shutdown_resources() # 覆盖依赖 app.dependency_overrides[get_container] = test_get_container # 发起请求验证 client = TestClient(app) response = client.get("/") assert response.json() == {"data": "fake data"} # 测试完记得清掉覆盖,别影响其他用例 app.dependency_overrides.clear()
方法二:直接用Dependency Injector的override功能替换服务
如果不想动原来的lifespan代码,也可以直接在测试前替换容器里的服务提供者:
def test_replace_container_service(): # 把容器里的service换成假服务实例 Container.service.override(FakeService()) client = TestClient(app) response = client.get("/") assert response.json() == {"data": "fake data"} # 测试完重置override Container.service.reset_override()
重要提醒
不管用哪种方法,测试结束后一定要清除依赖覆盖或者重置容器,不然会干扰其他测试用例的执行。
内容的提问来源于stack exchange,提问作者ajn
相关产品推荐
相关产品推荐

