应优先使用 pytest.raises 的 match 参数进行正则匹配校验异常消息,因其忽略格式差异、稳定性高;复杂断言或需访问异常属性时,必须用 as 绑定 exc_info 并手动检查。

必须用 pytest.raises 的 match 参数或手动检查 str(exc_info.value),不能靠全等比较字符串,也不能跳过上下文管理器直接调用函数。
用 match 参数做正则匹配最省心
它专为校验错误消息设计,忽略空格、换行、括号包裹等格式差异,稳定性高。
-
match是正则表达式匹配,不是子串查找,但写普通文本即可(如match="division by zero") - 不区分大小写?默认区分,需要时加
re.IGNORECASE:pytest.raises(ValueError, match=re.compile(r"invalid", re.IGNORECASE)) - 避免写完整 traceback,只抓关键语义词,比如
match="missing key"而不是"KeyError: 'missing'" - 多个可能消息?用
|写成match=r"not found|missing"
手动检查 str(exc_info.value) 适合复杂断言
当需要验证异常对象的属性(如 .code、.response)或做多条件判断时,必须用 as 绑定异常实例。
- 正确写法:
with pytest.raises(KeyError) as exc_info: d["missing"],然后assert "missing" in str(exc_info.value) - 别写
assert str(exc_info.value) == "missing"—— Python 3.12+ 对 KeyError 的字符串表示加了单引号,老版本没加,会脆 - 若异常带自定义字段(如
exc_info.value.status_code == 404),必须走as路径,match拿不到这些 -
exc_info.value是原始异常对象,可直接调用其方法或访问属性,不限于字符串
常见踩坑:错误消息断言失效的三种典型场景
不是代码写错,而是测试逻辑和 Python 异常机制不匹配导致的静默失败。
- 把函数调用提前写了:
result = my_func(); with pytest.raises(ValueError): pass—— 异常早抛出了,pytest.raises根本没机会捕获 - 用了
try/except包裹再断言:try: my_func(); assert False except ValueError: pass—— 没抛异常时测试通过,完全漏掉“应该抛却没抛”的 case - 在
with块里混了其他语句:with pytest.raises(ValueError): x = 1; my_func()—— 若x = 1先执行出错(比如 NameError),my_func()根本不会运行,误判成“没触发目标异常”
真正难的是让错误消息断言既稳定又精确:正则太宽泛会放过坏消息,字符串全等又太敏感。实际项目里,优先用 match 覆盖 90% 场景;剩下 10%,一定是异常带结构化字段,那时就得老老实实 as exc_info 并深入 inspect 它的属性。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











