You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FastAPI中pytest使用httpx AsyncClient异步测试的实现及报错解决

FastAPI 异步测试双报错解决方案

报错核心根因

  • RuntimeError: This event loop is already running:同步版TestClient内部逻辑会独立绑定/创建事件循环,和pytest-asyncio给异步测试用例分配的单例事件循环产生绑定冲突,属于客户端和测试框架的兼容逻辑问题,不是测试用例本身写错。
  • httpx.ConnectError: [Errno 8] nodename nor servname provided, or not known:旧版本httpx中,直接给AsyncClient传app=app参数时,不会自动切换到ASGI内存调用模式,反而会按照配置的base_url发起真实网络请求,在macOS等环境下解析0.0.0.0地址时会触发DNS解析失败,请求根本没走到本地的FastAPI应用逻辑。

可落地实现步骤

1. 对齐依赖版本避免兼容坑

  • 安装0.20及以上版本的httpx,该版本正式支持ASGITransport内存调用模式,无需发起真实网络请求即可测试ASGI应用
  • 匹配安装和当前pytest版本兼容的pytest-asyncio,避免异步测试执行逻辑异常

2. 修正异步客户端fixture写法

摒弃直接给AsyncClient传app=app的旧写法,改用官方推荐的ASGITransport绑定应用,完全在测试进程内存中处理请求,不会触发真实网络请求,也不会和pytest的事件循环产生冲突。
正确的fixture实现代码:

import pytest_asyncio
from httpx import AsyncClient, ASGITransport
from 你的项目路径.main import app  # 替换为实际的FastAPI应用导入路径

@pytest_asyncio.fixture(scope="module")
async def async_client():
    transport = ASGITransport(app=app)
    async with AsyncClient(transport=transport, base_url="http://testserver") as client:
        yield client

3. 修正测试用例的细节问题

  • 移除Python单元测试自带的assertEqual导入逻辑,直接使用pytest原生断言语法即可,避免导入冲突
  • 原有针对内部依赖的mock逻辑可以完整保留,ASGITransport的内存调用模式不会影响依赖mock的生效
    修正后的测试用例示例:
@pytest.mark.asyncio
@mock.patch('apps.core.views.requests.get', new=mocked_get_request)
async def test_get_non_json_response(async_client: AsyncClient):
    response = await async_client.get("/mymedia")
    assert response.json()['error']['message']['message'] == 'Not json'

额外避坑提示

  • 不要在异步测试流程中混用同步TestClient的调用逻辑,否则一定会触发事件循环重复绑定的报错
  • 如果路由依赖Redis等外部组件,需要在测试场景下通过FastAPI的依赖注入逻辑替换为测试用mock实例,不要让测试流程真的连接外部生产服务
  • 如果遇到模块级fixture的事件循环复用问题,可在pytest.ini配置文件中添加asyncio_mode = auto,匹配模块级fixture的事件循环作用域,避免循环重建异常

内容的提问来源于stack exchange,提问作者Marc LaBelle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.27 13:24:05