pytest.raises 是捕获并验证异常的最稳妥方式,需将待测代码置于 with 块内,支持类型检查、正则匹配错误消息及异常实例属性断言,严禁提前调用或混入无关逻辑。

用 pytest.raises 捕获并验证异常类型
直接用 pytest.raises 是最稳妥的方式,它不仅能确认异常被抛出,还能检查异常类型、消息内容,且自动处理异常未触发的失败场景。手动写 try/except 容易漏掉“没抛异常”的情况,导致测试通过但逻辑实际没走异常路径。
- 必须把待测代码放在
with pytest.raises(ZeroDivisionError):的with块内,不能提前调用或赋值给变量再断言 - 如果只关心类型,写
pytest.raises(ValueError)即可;若还要校验错误消息,加match参数:pytest.raises(ValueError, match="invalid literal") -
match使用正则匹配,不是全字匹配,所以写match="division by zero"就够了,不用写完整 traceback 信息
捕获异常实例并检查属性
有些异常带自定义字段(比如 requests.HTTPError.response 或自定义异常的 code 属性),这时得拿到异常对象本身。用 as 语法把异常绑定到变量,再做断言。
- 写法是
with pytest.raises(ConnectionError) as exc_info:,然后通过exc_info.value访问异常实例 -
exc_info.type是异常类,exc_info.value是异常实例,exc_info.traceback是 traceback 对象(一般不用) - 常见误操作:写成
assert exc_info == MyCustomError—— 错,exc_info是ExceptionInfo对象,不是异常本身
避免在函数调用外层包裹 pytest.raises
下面这种写法是错的:result = my_func(); with pytest.raises(...): result。因为 my_func() 已经执行完了,异常早在 with 块之前就抛出了,pytest 来不及捕获。
- 正确姿势是把调用放进
with块:with pytest.raises(...): my_func() - 如果函数需要参数,直接传进去:
with pytest.raises(KeyError): d['missing'] - lambda 包裹也行,但可读性差,仅适合极简场景:
with pytest.raises(TypeError): lambda: int('abc')—— 注意这里实际执行的是 lambda 调用,不是定义
注意上下文管理器退出时的异常吞吐行为
pytest.raises 本质是上下文管理器,它只捕获在 with 块内 *主动抛出* 的异常。如果块内有多个语句,只有第一个抛异常的会被捕获,后续语句不执行;但如果异常没按预期抛出,测试会立刻失败。
立即学习“Python免费学习笔记(深入)”;
- 别在里面混写无关逻辑,比如
with pytest.raises(...): do_something(); assert x == 1—— 若do_something()没抛异常,assert会执行,但测试已因未捕获异常而失败,这行 assert 实际不会影响结果,反而干扰判断 - 不要用
pytest.raises去“静默”吃掉异常来继续执行后续断言——这不是它的设计用途,真要这样,说明测试逻辑本身有问题


















