写异步测试的时候,最怕什么?不是逻辑复杂,而是明明写了 async def test_xxx,pytest 跑完显示“passed”,但实际什么都没测——只因为忘了加 await,或者 pytest 根本不认识它。今天就把这块的坑和正确操作一次性说清楚,省得你对着 RuntimeWarning 发呆。

先看最常见的报错场景:pytest 运行 async test 时弹出 RuntimeWarning: coroutine 'test_xxx' was never awaited。说白了,pytest 默认不认 async def 函数,你定义了一个协程,它却把它当普通函数调,结果协程对象被创建后没被 await,Python 自然就抛了警告,而测试还显示“passed”——实际上里面一行代码都没跑。

解决路径只有一条:让 pytest 知道该用 event loop 来跑它。别自己去写 loop.run_until_complete,交给插件处理更稳。

Python异步代码如何优雅地进行单元测试_配置pytest异步插件环境

async test 函数必须加 @pytest.mark.asyncio

不一定,但强烈建议加。不加的前提是:你用了 asyncio_mode = auto,且函数名符合 pytest 默认匹配规则(比如 test_*.py 里的 async def test_*)。

问题在于“auto”模式有边界:它只对模块级 async test 生效;如果 test 在 class 里、或函数带 fixture(尤其 session/scoped fixture),不加 mark 极大概率静默失败或 loop 复用出错。

一句话:但凡你拿不准,先把 mark 加上,总比 debug 半天强。

测试中调用 asyncio.sleep() 或真实 IO 导致测试变慢

异步测试慢,往往不是因为 asyncio 本身,而是你在 test 里真发了 HTTP 请求、连了 DB、或用了 asyncio.sleep(1) 模拟延迟——这会让单个 test 卡 1 秒,批量跑就不可接受。

正确做法是 mock 掉耗时协程,而不是降速跑真实逻辑。

fixture 返回 async 对象时,yieldreturn 怎么选

async fixture 不能用 yield,因为 yield 语句无法在 async def 里直接用 —— 你会看到 SyntaxError: 'yield' inside async function

正确方式是用 async def + return,清理逻辑单独写 teardown 函数,或用 async with 管理生命周期。

最常被忽略的是 event loop 的 scope。function 级 test 默认用独立 loop,但如果你写了 session-scoped async fixture,多个 test 共享同一个 loop,中间任何未 await 的协程残留都会导致后续 test 报 RuntimeError: Event loop is closed——这种问题不会立刻暴露,得看 CI 上的偶发失败。所以,scope 的配置一定要和你的实际资源生命周期对齐,别偷懒。

本文转载于:https://www.php.cn/faq/2314865.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。