pytest.raises“捕获不到”异常是因为错误地先执行了函数(如pytest.raises(...)(func())),正确用法是with pytest.raises(...): func()或装饰器,需由它控制调用时机。

pytest.raises 为什么有时“捕获不到”异常
直接用 pytest.raises 包裹普通函数调用却没报错,大概率是因为你写了类似 pytest.raises(ValueError)(func()) 这种写法——这其实是在调用 func() 后才把返回值传给 pytest.raises,异常早抛出了,根本没被接住。
正确姿势是让 pytest.raises 管理整个执行过程。它本质是个上下文管理器或装饰器,必须控制函数的**调用时机**。
- ✅ 正确:用
with pytest.raises(ValueError): func() - ✅ 正确:用装饰器
@pytest.mark.parametrize(...)+with pytest.raises(...)套住测试函数体 - ❌ 错误:写成
pytest.raises(ValueError, match="xxx")(func())——func()已执行完毕 - ❌ 错误:漏掉
with,只写pytest.raises(TypeError)单独一行,它不会做任何事
如何校验异常类型和错误信息
pytest.raises 支持两个关键参数:match(正则匹配)和异常类本身(类型检查)。二者可同时用,但注意 match 只作用于 str(exception),不是 exception.args[0] 的原始值(虽然多数时候一样)。
- 只检查类型:
with pytest.raises(KeyError): d['missing'] - 检查类型 + 消息(正则):
with pytest.raises(ValueError, match=r'expected \d+ got \d+'): -
match不区分大小写?不,默认区分;要忽略大小写得写match=r'(?i)not found' - 如果异常消息含换行符,
match默认不跨行匹配;需加(?s)修饰符才能让.匹配换行
捕获后还想检查异常对象本身
有时候光知道“抛了 ValueError”不够,你还想验证它的 args、自定义属性或是否继承自某个基类。这时得把异常对象“抓出来”:
with pytest.raises(ValueError) as exc_info:
int('abc')
assert 'invalid literal' in str(exc_info.value)
assert exc_info.type is ValueError
assert isinstance(exc_info.value, ValueError)
exc_info 是个 ExceptionInfo 对象,有三个常用属性:.type(异常类)、.value(异常实例)、.traceback(可选,用于深度断言)。
- 别写
exc_info.value.args[0]来取消息——万一异常没args或为空会报IndexError;用str(exc_info.value)更健壮 - 如果被测代码可能抛不同异常,但你只想处理其中一种,不能靠
except去包——那是单元测试逻辑,应由pytest.raises显式声明预期
在参数化测试中使用 pytest.raises
配合 @pytest.mark.parametrize 时,常见错误是把 pytest.raises 写在参数里,或者试图对每个输入动态构造上下文块。其实最稳的方式是:参数决定“是否期望异常”,然后在测试体内统一用 with + 条件判断。
@pytest.mark.parametrize("input_val,should_raise", [
("123", False),
("abc", True),
])
def test_parse_int(input_val, should_raise):
if should_raise:
with pytest.raises(ValueError):
int(input_val)
else:
assert isinstance(int(input_val), int)
更进阶的做法是用 pytest.raises 的返回值做布尔判断(但它不返回布尔!),所以别写 if pytest.raises(...):——语法错误。
真正容易被忽略的是:当参数化数据量大时,match 正则写错会导致整条测试静默通过(因为没匹配上就不算失败),建议对关键错误消息单独写断言,或用 print(str(exc_info.value)) 临时调试。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











