pytest.raises未捕获异常是因为目标代码未置于with块内;正确写法是with pytest.raises(valueerror): bad_func(),否则异常无法被监测和断言。

pytest.raises 为什么没捕获到异常?
直接写 pytest.raises(ValueError) 但测试通过了,实际代码却没抛异常——这是因为 pytest.raises 默认只检查「被包裹的代码块是否抛出指定异常」,不关心它是否「应该抛」。常见错误是忘了把要测的函数调用放进 with 块里,比如:
def test_bad():
pytest.raises(ValueError) # ❌ 这行什么都没做
bad_func() # 即使这里抛异常,也不会被捕获断言
正确做法必须让目标代码处于 with 上下文中:
def test_good():
with pytest.raises(ValueError):
bad_func() # ✅ 异常发生在这里才被监测
- 如果
bad_func()没抛ValueError,测试直接失败,报错类似Failed: DID NOT RAISE <class></class> - 如果抛的是其他异常(如
TypeError),同样失败,提示异常类型不匹配 -
pytest.raises不会吞掉异常——它只是验证发生与否,不影响后续执行流
如何获取并检查异常的具体信息?
光知道抛了异常不够,往往要确认错误消息、属性或上下文。用 as 捕获异常实例:
def test_error_message():
with pytest.raises(ValueError) as exc_info:
raise ValueError("invalid input: age must be > 0")
assert "age" in str(exc_info.value)
assert exc_info.type is ValueError
-
exc_info.value是异常对象本身,可用来断言str()、args或自定义属性 -
exc_info.type是异常类,适合做类型判断(比如区分ValueError和子类) -
exc_info.traceback可访问原始 traceback,但极少需要;多数情况用不到 - 注意:不要在
with块外访问exc_info.value,它只在块退出后才可用
pytest.raises 能不能测异步函数?
不能直接用。对 async def 函数,pytest.raises 无法 await,会报 RuntimeWarning: coroutine 'xxx' was never awaited 或直接断言失败。
仅使用 Python 将 Claw Code 虚拟化框架与 OpenClaw 集成,提供 184 种工具和 200 多条命令,用于安全分析和代码质量...
- 错误写法:
with pytest.raises(ValueError): async_func() - 正确做法是用
await包裹,并配合pytest-asyncio插件(确保测试函数加@pytest.mark.asyncio):@pytest.mark.asyncio async def test_async_raises(): with pytest.raises(ValueError): await async_func() - 若不用插件,可手动
asyncio.run(),但会丢失 traceback 精度,不推荐 - 注意:Python 3.11+ 的
ExceptionGroup需用pytest.raises(ExceptionGroup),但需确保 pytest ≥ 7.4 且异常确实以 group 形式抛出
为什么 assertRaises 有时比 pytest.raises 更合适?
不是所有场景都该用 pytest.raises。当你要测「某个方法调用时,另一个被 mock 的函数是否抛异常」,用 unittest.mock.patch + self.assertRaises 更直白:
from unittest.mock import patch
<p>def test_mocked_call_raises():
with patch("module.func") as mock_f:
mock_f.side_effect = ValueError("boom")
with pytest.raises(ValueError): # ✅ 可行
target_function()</p>
但如果你已用 pytest 主导项目,没必要为这点切回 unittest 风格。真正要注意的是:当异常来自第三方库内部、且你无法控制调用时机(比如信号处理、atexit 回调),pytest.raises 会失效——它只能捕获同步、显式调用路径上的异常。
这种情况下得改用日志捕获、临时重载 sys.excepthook,或者干脆重构被测代码,把异常逻辑抽成可测函数。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










