pytest.raises 不能直接用于 assert 后,因 raise 是语句且抛异常会中断执行;必须用上下文管理器(with)或函数式写法捕获异常,以验证类型、消息等。

pytest.raises 为什么不能直接写成 assert raise
因为 Python 的 raise 是语句,不是表达式,没法放进 assert 后面;而且异常一旦抛出就中断执行,没机会做断言。所以必须用上下文管理器或函数式写法捕获它——pytest.raises 就是专干这事的。
两种写法:with 语句 vs 函数调用
最常用的是 with 语法,清晰、易读、能检查异常类型和消息:
def test_divide_by_zero():
with pytest.raises(ZeroDivisionError):
1 / 0
如果还要验证异常信息,加 match 参数(正则匹配):
with pytest.raises(ValueError, match=r"invalid literal.*base 10"):
int("abc")
函数式写法适合单行调用,但无法检查异常内容:
仅使用 Python 将 Claw Code 虚拟化框架与 OpenClaw 集成,提供 184 种工具和 200 多条命令,用于安全分析和代码质量...
pytest.raises(KeyError, lambda: d["missing"])- 注意:传的是可调用对象,不是调用结果(别写成
d["missing"]) - 返回一个异常实例,可进一步断言:
excinfo = pytest.raises(...); assert "key" in str(excinfo.value)
常见踩坑点
这几个问题一不小心就让测试“假通过”或直接报错:
- 忘记在
with块里实际触发异常——代码没抛出,测试就失败 - 用了
pytest.raises却没做任何事,比如with pytest.raises(ValueError): pass→ 测试必 fail -
match是正则,不是子串匹配;要匹配特殊字符得转义,比如match=r"list index.*-1" - 异步函数不能直接用
with pytest.raises,得用pytest-asyncio配合await和async with - 捕获父类异常(如
Exception)容易掩盖真实问题,尽量精确到具体异常类型
如何测试“不该抛异常”的情况
有时你得确保某段代码**不抛异常**,这反而容易被忽略:
- 直接运行即可,不加
pytest.raises—— 如果抛了,测试自然失败 - 想显式声明“应静默成功”,可用
does_not_raise()(需从pytest导入),配合参数化测试更清晰:
from pytest import raises, does_not_raise
@pytest.mark.parametrize("value,expectation", [
(5, does_not_raise()),
(-1, raises(ValueError)),
])
def test_validate_age(value, expectation):
with expectation:
validate_age(value)
这里的关键是:does_not_raise() 不是摆设,它让测试逻辑对称,也避免误把异常当正常流程。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










