pytest.raises未捕获异常的主因是异常被吞掉或未执行到报错路径;正确用法须将被测函数调用置于with块内,并用exc_info校验类型、消息(推荐in子串匹配)和属性;优先使用上下文管理器而非函数式调用。

pytest.raises 为什么没捕获到异常
直接写 pytest.raises(ValueError) 但测试通过了,说明异常根本没抛出——常见原因是被内部 try...except 吞掉了,或者函数压根没走到报错路径。要确认异常是否真发生,先去掉 pytest.raises,让测试自然崩溃看堆栈。
另一个高频问题是作用域:把被测函数调用写在 with pytest.raises(...) 外面,比如:
func_that_raises() # 这里异常已抛出并中断执行
with pytest.raises(ValueError):
pass # 永远不会进到这里正确写法必须是异常发生在 with 块内:
with pytest.raises(ValueError) as exc_info:
func_that_raises()如何校验异常的类型、消息和属性
pytest.raises 返回一个上下文管理器,用 as exc_info 捕获后,能访问异常实例的全部属性。
立即学习“Python免费学习笔记(深入)”;
-
exc_info.type是异常类,比如ValueError -
exc_info.value是异常对象,可调用str(exc_info.value)取消息字符串 -
exc_info.traceback是 traceback 对象,调试时有用
校验消息推荐用 in 判断子串,避免因空格、换行或细节变动导致误失败:
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
with pytest.raises(ValueError) as exc_info:
parse_config("invalid: yaml")
assert "yaml" in str(exc_info.value)
assert exc_info.type is ValueErrorpytest.raises 与函数式调用的区别
pytest.raises 支持两种用法:上下文管理器(推荐)和函数式调用。后者容易踩坑:
- 函数式写法:
pytest.raises(ValueError, func_that_raises, "arg1", key="val")—— 参数全得塞进调用里,无法捕获返回值,且不支持关键字参数透传(会报TypeError: got an unexpected keyword argument) - 上下文管理器更灵活,还能嵌套、加条件判断,甚至配合
capsys检查日志输出
除非旧项目强依赖函数式风格,否则一律用 with 块。
处理多个可能异常或部分路径不抛异常
一个函数在不同输入下可能抛不同异常,或某些输入根本不抛异常。这时不能硬写死 pytest.raises,得拆开测:
- 对明确应抛
TypeError的输入,单独写一个测试用pytest.raises(TypeError) - 对合法输入,就正常调用并断言返回值,不加
pytest.raises - 如果想“确保某路径不抛异常”,直接调用即可;若意外抛了,测试自然失败,无需额外断言
别试图用 pytest.raises(Exception) 捕所有异常来“兜底”——这会让真正不该发生的错误被掩盖,违背测试的明确性原则。
最易忽略的是异常消息的稳定性:有人直接 assert str(exc_info.value) == "expected msg",但只要上游改了个标点,测试就挂。用子串匹配、正则或只校验关键字段,才是可持续的做法。

















