十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

FastAPI 事件测试指南:用 TestClient 触发 lifespan 与 startup/shutdown 事件

FastAPI 事件测试指南:用 TestClient 触发 lifespan 与 startup/shutdown 事件 FastAPI 事件测试指南用 TestClient 触发 lifespan 与 startup/shutdown 事件【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi在编写 FastAPI 应用测试时事件钩子lifespan、startup、shutdown是否会在测试中被真正执行直接决定了测试的有效性——数据库连接、缓存初始化、内存数据装载等副作用都发生在这里。本篇指南讲解如何在测试中使用TestClient的with语句让lifespan事件正常运行以及针对已弃用的startup/shutdown事件的处理方式并结合 FastAPI 仓库源码说明事件参数的注册位置与弃用标记的实现帮助你写出能完整验证启动即有数据、关闭即清理行为的测试。为什么测试中需要显式触发 lifespanFastAPI 应用的事件钩子通常用于在应用启动时做初始化连接数据库、加载配置、填充缓存在应用停止时做清理。当应用以测试客户端而非真实 ASGI 服务器驱动时事件是否执行取决于测试代码如何构造TestClient。FastAPI 测试套件中的约定是只有把TestClient放在with语句上下文管理器中使用时lifespan 事件才会被执行。这对应真实服务器启动应用 → 处理请求 → 终止应用的完整生命周期。这一点在 FastAPI 的事件参数定义中也有体现fastapi/applications.py 中FastAPI.__init__的lifespan参数文档明确说明它是一个Lifespan上下文管理器处理器用于替代startup和shutdown函数列表将两者合并为单个上下文管理器lifespan: Annotated[ Lifespan[AppType] | None, Doc( A Lifespan context manager handler. This replaces startup and shutdown functions with a single context manager. ), ] None,用 with 语句在测试中运行 lifespan当你的测试需要lifespan被执行时把TestClient(app)放在with语句中即可。下面的完整示例来自 docs_src/app_testing/tutorial004_py310.py它在一个异步上下文管理器中完成初始化与清理并在测试里断言事件各阶段的副作用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] def 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块之前lifespan 尚未开始共享状态items仍为空字典with TestClient(app) as client:块内进入块时 lifespan 的yield之前部分已经执行完毕items被填充此时发起请求能正常拿到数据且请求完成后数据依然存在说明清理还没发生with块结束后退出块模拟应用被终止lifespan 的yield之后部分执行items.clear()生效断言共享状态恢复为空。也就是说with语句的进入点触发启动逻辑退出点触发关闭逻辑测试可以在两个边界处分别断言副作用从而验证初始化和清理两条路径都按预期工作。该测试函数本身也是 pytest 可直接执行的测试用例仓库中的 tests/test_tutorial/test_testing/test_tutorial004.py 直接导入并调用它来验证整个流程from docs_src.app_testing.tutorial004_py310 import test_read_items def test_main(): test_read_items()如果你希望了解with TestClient(app)触发 lifespan 的底层机制其基于 ASGI 的asgi.lifespan协议实现官方 Starlette 文档站的 Running lifespan in tests 一节有详细说明FastAPI 的TestClient即直接复用 Starlette 的实现见下文源码分析。已弃用的 startup / shutdown 事件如何测试对于已弃用的startup与shutdown事件通过app.on_event(startup)/app.on_event(shutdown)装饰器注册测试方式与上面一致同样把TestClient(app)放入with语句中即可触发事件。示例来自 docs_src/app_testing/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}需要强调的是on_event已经是**弃用deprecated**写法。从源码看fastapi/applications.py 中的FastAPI.on_event方法被deprecated装饰器包裹警告信息明确指出on_event is deprecated, use lifespan event handlers instead其实现只是转发给self.router.on_event(event_type)同样FastAPI.__init__的on_startup/on_shutdown参数文档fastapi/applications.py也注明应改用lifespan处理器。新代码应统一采用lifespan写法上面这段startup事件示例主要用于帮助维护既有代码时的测试以及理解旧事件与新 lifespan 在测试层面行为的一致性。源码与测试佐证TestClient 的来源。fastapi/testclient.py 只有一行核心实现from starlette.testclient import TestClient as TestClient # noqa即 FastAPI 的TestClient完全由 Starlette 提供with TestClient(app)触发 lifespan 的能力继承自 Starlette 测试客户端的 ASGI lifespan 支持FastAPI 层没有额外封装。弃用警告在测试中的体现。由于on_event会发出DeprecationWarning仓库测试 tests/test_tutorial/test_testing/test_tutorial003.py 在导入该示例时用pytest.warns(DeprecationWarning)显式包裹验证了弃用标记确实生效import pytest def test_main(): with pytest.warns(DeprecationWarning): from docs_src.app_testing.tutorial003_py310 import test_read_items test_read_items()lifespan 的更多行为验证。tests/test_router_events.py 中还覆盖了 lifespan 在APIRouter嵌套场景下的行为如test_app_lifespan_state、test_router_nested_lifespan_state、test_router_sync_generator_lifespan等包括 Router 级 lifespan 与 App 级 lifespan 的合并、父级覆盖子级 state 等情况。如果你的应用把部分初始化逻辑放在APIRouter(lifespan...)上这些测试用例可以作为编写对应测试时的参照。小结测试中需要 lifespan 事件运行 → 用with TestClient(app) as client:进入块触发启动逻辑退出块触发关闭逻辑旧式app.on_event(startup/shutdown)已弃用源码中的deprecated标记可证测试写法相同但新代码应迁移到lifespan在with块的三个位置进入前、块内、退出后分别断言共享状态即可完整覆盖初始化 → 服务请求 → 清理整个事件生命周期相关示例与验证代码位于 docs_src/app_testing/tutorial004_py310.py、docs_src/app_testing/tutorial003_py310.py 及 tests/test_tutorial/test_testing/。【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表