Python 3.11 中 pytest-asyncio 异步测试必须满足三条件:安装插件、配置 asyncio_mode = "auto"、测试函数为 @pytest.mark.asyncio 标记的 async def;缺一即同步执行,await 不生效。

Python 3.11 中用 pytest-asyncio 写异步测试,核心不是“新语法”,而是必须满足三个硬性条件:插件已安装、asyncio_mode = auto 已配置、测试函数带 @pytest.mark.asyncio 且是 async def。漏掉任一环,测试就只是被当成普通函数调用,连 await 都不会执行。
pytest-asyncio 不生效?先检查这三件事
很多人写了 @pytest.mark.asyncio 却发现协程没运行、只报 RuntimeWarning: coroutine 'test_xxx' was never awaited,还显示 “PASSED”——这是典型配置缺失。
- 没装插件:
pip install pytest-asyncio(注意不是pytest_asyncio或其他变体) - 没配模式:在项目根目录的
pyproject.toml里加:[tool.pytest.ini_options] asyncio_mode = "auto"
或在pytest.ini里写:[tool:pytest] asyncio_mode = auto
- 测试函数不是
async def:哪怕只差一个async关键字,@pytest.mark.asyncio就会被忽略,pytest 直接跳过或静默当同步函数跑
async fixture 怎么写才不崩?别 yield,用 return
异步 fixture 和同步 fixture 行为完全不同:不能 yield,不能混用 time.sleep 这类同步阻塞,也不能在 return 前留未 await 的协程。
- 必须用
async def定义,且结尾用return(不是yield):@pytest.fixture async def db_conn(): conn = await asyncpg.connect(DSN) return conn # ✅ 正确 - 若需清理,得另写一个
async deffixture +scope="function"控制生命周期,或者把清理逻辑包进被测服务里(比如用async with) - 调用时必须
await:db = await db_conn,不能直接传参;否则会报TypeError: object can't be used in 'await' expression
测试 ExceptionGroup 要升级 pytest ≥7.4.0
Python 3.11 的 ExceptionGroup 在旧版 pytest 里完全不可见——pytest.raises(ValueError) 对它无效,pytest.raises(ExceptionGroup) 也会因版本太低而报错或静默失败。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
- 先确认版本:
pip show pytest,确保Version: 7.4.0或更高 - 捕获组本身:
with pytest.raises(ExceptionGroup, match="eg"):—— 注意match匹配的是组名,不是内部异常消息 - 检查内部异常构成,得手动展开:
with pytest.raises(ExceptionGroup) as exc_info: raise ExceptionGroup("eg", [ValueError("bad"), TypeError("boom")]) assert isinstance(exc_info.value.exceptions[0], ValueError) - 别在普通
def测试里直接await asyncio.gather(...)后套pytest.raises(ExceptionGroup):必须用@pytest.mark.asyncio+async def,否则事件循环不启动,异常根本不会抛出
调试 breakpoint() 进不去?加 --pdb 并确保标记正确
breakpoint() 在异步函数里默认不触发,不是代码问题,是 pdb 不知道怎么挂起协程上下文。
- 最简方案:
pytest --pdb test_file.py::test_name,前提是该函数已正确标记为@pytest.mark.asyncio且是async def - 别在
async def里写import pdb; pdb.set_trace()后直接运行——它可能卡住或跳过,因为没进入协程调度上下文 - VS Code 用户:确保
launch.json的"type"是"python",且启用了"justMyCode": true,否则断点可能落在 asyncio 底层代码里
最容易被忽略的一点:asyncio_mode = auto 是“自动识别”,但不是“自动启用”。它只对带 @pytest.mark.asyncio 的 async def 生效;如果项目里混用同步/异步测试,建议显式加标记,避免 CI 或 IDE 因解析偏差跳过异步用例。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










