如何复用AsyncClient Fixture?FastAPI测试注入异常问题排查
解决FastAPI异步测试中Session级AsyncClient Fixture异常问题
错误原因分析
你遇到的AttributeError: 'async_generator' object has no attribute 'get'由两个核心问题导致:
- lifespan调用方式错误:FastAPI的
lifespan是绑定应用实例的生命周期钩子,无需手动调用上下文管理器;且你定义的lifespan的yield没有返回值,导致传入AsyncClient的app参数为None。 - 缺少Session级事件循环:Session级异步Fixture需要配套的Session级事件循环,否则pytest无法正确解析Fixture返回值,将
AsyncClient实例误识别为async_generator对象。
修正后的代码
from contextlib import asynccontextmanager from fastapi import FastAPI import asyncio from httpx import AsyncClient import pytest @asynccontextmanager async def lifespan(app: FastAPI): print("starting up") yield print("shutting down") app = FastAPI(lifespan=lifespan) @app.get("/hello") async def hello(): await asyncio.sleep(2) return {"hello": "world"} # 定义Session级事件循环,保证异步Fixture跨用例复用 @pytest.fixture(scope="session") def event_loop(): loop = asyncio.get_event_loop_policy().new_event_loop() yield loop loop.close() # 修正后的Session级AsyncClient Fixture @pytest.fixture(scope="session") async def client(): # 直接传入app实例,FastAPI自动处理lifespan生命周期 async with AsyncClient(app=app, base_url="http://testserver") as client: yield client @pytest.mark.asyncio async def test_hello(client): response = await client.get("/hello") assert response.json() == {"hello": "world"}
关键修正点
- 移除手动调用lifespan:
AsyncClient加载app实例时,FastAPI会自动触发lifespan的启动和关闭逻辑,无需手动管理。 - 添加Session级事件循环:确保Session内所有异步测试共用同一个事件循环,保证Session级Fixture的正常复用。
- 简化Fixture逻辑:直接在
AsyncClient的上下文管理器中yield实例,避免嵌套上下文导致的解析异常。
验证运行
执行pytest后,控制台会输出:
starting up . shutting down
测试用例会正常通过,且lifespan仅在Session启动和关闭时各执行一次,实现了Fixture的Session级复用。
内容的提问来源于stack exchange,提问作者Michael Xia
相关产品推荐
相关产品推荐

