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

pytest测试调用asyncio协程的普通函数出现无事件循环错误如何解决

问题根因
  • Mock路径错误:你需要Mock的是sample模块中实际引用的asyncio.create_subprocess_shell,而不是全局asyncio库下的对应方法,这是单元测试Mock的通用规则,必须指向业务代码实际调用的导入路径。
  • 模拟对象缺失必要属性:你自定义的AsyncMock返回结果没有模拟子进程对象的returncode属性,sample_async访问该属性时触发异常,间接导致事件循环提前销毁,抛出无可用事件循环的错误。
  • 额外优化点:你已经单独完成了sample_async的单元测试,测试launcher时不需要真实执行异步协程逻辑,直接Mockasyncio.run可以完全避开事件循环相关问题。
解决方案

方案1:直接Mock asyncio.run(推荐)

该方案仅验证launcher的分支逻辑,不需要处理任何异步相关适配,性能最高且不会触发事件循环错误:

from unittest.mock import patch
import sample

def test_launcher_async_branch():
    # Mock sample模块中调用的asyncio.run
    with patch("sample.asyncio.run") as mock_run:
        # 自定义协程执行返回值
        mock_run.return_value = 0
        res = sample.launcher("async", "/bin/bash ls")
        # 验证逻辑
        mock_run.assert_called_once()
        assert res == 0

def test_launcher_sync_branch():
    res = sample.launcher("no_asyncio", "")
    assert res == 0

方案2:保留真实异步执行逻辑

如果你需要验证sample_async和子进程调用的链路正确性,可修正Mock配置实现:

from unittest.mock import patch, MagicMock
import sample

class AsyncMock(MagicMock):
    async def __call__(self, *args, **kwargs):
        # 构造带returncode属性的模拟子进程对象
        mock_proc = MagicMock()
        mock_proc.returncode = 0
        return mock_proc

# 修正patch路径为sample模块内的asyncio.create_subprocess_shell
@patch("sample.asyncio.create_subprocess_shell", new_callable=AsyncMock)
def test_launcher_full_link(mock_shell):
    res = sample.launcher("async", "/bin/bash ls")
    # 验证子进程调用参数
    mock_shell.assert_called_once_with("/bin/bash ls")
    assert res == 0

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 08:36:01