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

pytest异步测试未await async fixture导致接口偶发404问题

问题根因

偶发404本质是异步fixture生命周期和测试用例事件循环绑定异常,不是fixture完全没被await,而是三类竞态问题导致fixture返回时插入操作实际未完成:

  • pytest-asyncio 0.19及以上版本默认不会自动将未显式标记的异步fixture纳入测试用例的同事件循环调度,高并发跑批量用例时,偶发fixture协程被调度到已关闭的事件循环上,拿到inserted_id但插入流程未走完就进入测试逻辑
  • 每次执行插入操作都新建AsyncIOMotorClient实例,连接建立、写入确认的异步流程没有和fixture返回时机强绑定,30个用例并行时连接池资源竞争会放大写入延迟,出现「返回了ID但数据还没落库」的情况
  • PyCharm内置pytest运行器对原生pytest.fixture定义的异步fixture钩子兼容有问题,部分场景会直接返回未执行的协程对象,而不是等协程跑完再传值给测试用例

解决步骤

1. 配置pytest-asyncio全局自动异步模式

在项目根目录新建或修改pytest.ini,添加如下配置,强制所有异步测试、异步fixture自动在同一事件循环内调度,不需要逐个加@pytest.mark.asyncio标记:

[pytest]
asyncio_mode = auto

2. 替换异步fixture的装饰器

所有异步fixture不要用原生@pytest.fixture装饰,改用pytest_asyncio.fixture,从根源解决PyCharm运行器和pytest对异步fixture的识别差异。修改后的测试数据fixture参考:

import pytest_asyncio
from motor.motor_asyncio import WriteConcern

# 从conftest导入全局复用的测试Mongo客户端,不要每次新建
@pytest_asyncio.fixture
async def add_mock_topic(test_mongo_client):
    database = test_mongo_client[settings.TEST_DATABASE]
    collection = database.get_collection("topics_collection")
    # 显式指定写入确认级别,等数据真正写入主节点再返回
    res = await collection.with_options(write_concern=WriteConcern(w=1)).insert_one({
        "name": "TestName",
        "description": "test description"
    })
    # 插入后主动校验数据存在,彻底消除竞态窗口
    assert await collection.find_one({"_id": res.inserted_id}) is not None
    yield res
    # 测试完成后直接清理当前测试数据,比独立的cleanup fixture时序更可靠
    await collection.delete_one({"_id": res.inserted_id})

3. 全局复用Mongo测试客户端

不要在每个增删改查的工具函数里新建AsyncIOMotorClient,在conftest.py里定义会话级的共享客户端,整个测试流程复用同一个连接池,避免频繁建连带来的延迟:

# conftest.py
import motor.motor_asyncio
import pytest_asyncio

@pytest_asyncio.fixture(scope="session")
async def test_mongo_client():
    client = motor.motor_asyncio.AsyncIOMotorClient(MONGO_DETAILS)
    # 启动时等待连接可用
    await client.admin.command("ping")
    yield client
    # 所有测试结束后关闭连接
    client.close()

4. PyCharm运行器兼容设置

打开PyCharm设置 -> 工具 -> Python集成工具,将默认测试运行器设置为pytest;编辑测试运行配置,将工作目录指向项目根目录,在环境变量中添加PYTEST_ASYNCIO_MODE=auto,避免运行器未读取pytest.ini配置导致的调度异常。


改完之后连续执行多次全量测试即可验证效果。之前把插入逻辑直接写在测试用例内部能稳定运行,本质是插入操作和测试请求在同一个协程调用链上,不存在跨fixture的事件循环调度错位,按上述配置修改后,fixture的执行时序和在测试用例内直接await的效果完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.31 00:06:24