FastAPI 如何在测试中运行 lifespan 启动与关闭事件?

发布时间:2026/9/12 20:58:23
FastAPI 如何在测试中运行 lifespan 启动与关闭事件? FastAPI 如何在测试中运行 lifespan 启动与关闭事件【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi如果你的 FastAPI 应用通过lifespan参数在启动时加载共享资源比如数据库连接池、机器学习模型那么在测试里直接调用TestClient(app)发请求时这些启动逻辑并不会执行——因为lifespan没有被触发。FastAPI 官方文档给出的解决方法是把TestClient放进with语句中使用进入with块时运行lifespan中yield之前的启动代码退出with块时模拟应用终止并运行yield之后的关闭代码。本文基于 Testing Events 文档 与 Lifespan Events 文档 给出完整可运行的测试写法。前提用 lifespan 定义应用lifespan是一个用asynccontextmanager装饰的、带yield的异步函数通过FastAPI的lifespan参数传入。yield之前的代码在应用开始接收请求之前执行一次yield之后的代码在应用停止处理请求时执行一次。官方示例完整源码from contextlib import asynccontextmanager from fastapi import FastAPI from fastapi.testclient import TestClient items {} asynccontextmanager async def lifespan(app: FastAPI): items[foo] {name: Fighters} items[bar] {name: Tenders} yield # clean up items items.clear() app FastAPI(lifespanlifespan) app.get(/items/{item_id}) async def read_items(item_id: str): return items[item_id]需要说明的限制如果你传入了lifespan参数startup和shutdown事件处理器将不再被调用——是lifespan和事件二选一不能同时生效。核心写法把 TestClient 放进 with 语句官方文档给出的关键做法是一行用with TestClient(app) as client:替代直接调用TestClient(app)。上面的应用对应的测试完整文件见 tutorial004_py310.pydef test_read_items(): # Before the lifespan starts, items is still empty assert items {} with TestClient(app) as client: # Inside the with TestClient block, the lifespan starts and items added assert items {foo: {name: Fighters}, bar: {name: Tenders}} response client.get(/items/foo) assert response.status_code 200 assert response.json() {name: Fighters} # After the requests is done, the items are still there assert items {foo: {name: Fighters}, bar: {name: Tenders}} # The end of the with TestClient block simulates terminating the app, so # the lifespan ends and items are cleaned up assert items {}断言的位置体现了lifespan在测试中的执行时机这也是判断写法是否正确的依据with块之前items {}说明启动代码尚未运行with块内部lifespan已启动items中已有foo、bar两个值请求/items/foo返回 200 且 JSON 为{name: Fighters}退出with块之后TestClient模拟应用终止lifespan中yield之后的清理代码执行items变回空字典。运行与验证测试用 pytest 运行官方文档中的运行命令为$ uv run pytest成功条件是上述断言全部通过进入with块前后items的内容变化、请求状态码与响应体、以及退出with块后items被清空。已废弃的 startup / shutdown 事件写法如果你的应用仍在使用已废弃的app.on_event(startup)事件见 events 文档TestClient的with用法同样适用测试写法不变只是应用定义改为事件形式完整文件见 tutorial003_py310.pyfrom fastapi import FastAPI from fastapi.testclient import TestClient app FastAPI() items {} app.on_event(startup) async def startup_event(): items[foo] {name: Fighters} items[bar] {name: Tenders} app.get(/items/{item_id}) async def read_items(item_id: str): return items[item_id] def test_read_items(): with TestClient(app) as client: response client.get(/items/foo) assert response.status_code 200 assert response.json() {name: Fighters}文档同时建议对于启动和关闭相互关联的逻辑获取资源后释放资源应改用lifespan而不是两个独立的事件函数。边界与限制异步测试中AsyncClient不触发 lifespan。Async Tests 文档 明确警告如果测试函数是async def并使用AsyncClientTestClient的那套魔法不再工作AsyncClient不会触发 lifespan 事件文档建议改用 florimondmanca/asgi-lifespan 提供的LifespanManager来确保事件被触发。如果你的测试是普通def函数并使用TestClient则不受此限制。子应用不执行 lifespan 事件。events 文档 指出lifespan 事件只会在主应用上执行不会为通过 Mount 挂载的子应用执行。更多底层细节ASGI Lifespan Protocol可参考 Testing Events 文档 中指向的 Starlette 官方文档。完整的 lifespan 定义方式含模型加载用例见 docs/en/docs/advanced/events.md可运行的测试源码在 docs_src/app_testing/tutorial004_py310.py。【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询