FastAPI异步测试报错:AttributeError: 'NoneType'对象无'send'属性
问题原因
- AsyncClient实例复用导致状态异常:如果AsyncClient被设置为
module或class级别的pytest fixture,第一个测试结束后客户端连接会被自动关闭,第二个测试时实例内部的连接对象已变为None,调用请求方法时触发AttributeError: 'NoneType' object has no attribute 'send'。 - 数据库会话未做测试隔离:测试间未回滚/关闭数据库会话,导致连接池耗尽或会话状态污染,间接影响AsyncClient的请求处理流程。
解决方法
1. 配置Function级别的AsyncClient Fixture
强制每个测试用例生成全新的AsyncClient实例,彻底避免状态复用:
import pytest from httpx import AsyncClient from main import app @pytest.fixture(scope="function") # 核心:每个测试都创建新客户端 async def async_client(): async with AsyncClient(app=app, base_url="http://test") as client: yield client
2. 实现数据库会话的测试隔离
每个测试后回滚数据并关闭会话,防止连接泄露和数据污染:
from sqlalchemy.ext.asyncio import AsyncSession from your_db_module import async_session_factory @pytest.fixture(scope="function") async def db_session(): session = async_session_factory() try: yield session finally: await session.rollback() # 回滚测试数据,不影响其他用例 await session.close()
3. 修复TestClient的异步用法(可选)
如果之前因用法错误放弃TestClient,可改用其官方异步API:
from fastapi.testclient import TestClient from main import app client = TestClient(app) async def test_async_create_item(): response = await client.async_post("/items/", json={"name": "test"}) assert response.status_code == 200
4. 检查端点的数据库依赖注入
确保FastAPI端点使用请求级别的会话,而非全局实例:
from fastapi import Depends from sqlalchemy.ext.asyncio import AsyncSession from your_db_module import async_session_factory async def get_db(): async with async_session_factory() as session: yield session @app.post("/items/") async def create_item(item: Item, db: AsyncSession = Depends(get_db)): # 业务逻辑实现 pass
报错验证
若报错栈指向httpx内部的send方法,基本可确认是AsyncClient实例已被关闭。使用function级fixture后,每个测试都会重新初始化客户端,彻底解决状态无效问题。
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

