最简单的方法是用 raise 直接抛异常;需配合 assertraises 或 pytest.raises 断言,确保异常发生在被测代码路径内;mock.patch 应指定被测模块中导入的位置,并用 side_effect 设置异常;pytest.raises 支持检查异常属性,避免仅断言类型;禁用手写 try/except。

用 raise 在测试函数里直接抛异常最简单
单元测试里想验证某段代码是否正确捕获了特定异常,最直白的做法就是在被测逻辑的模拟路径中主动抛出它。不需要动真实业务代码,也不依赖外部状态。
常见错误是试图在测试里调用真实会出错的函数(比如读不存在的文件),这会让测试变慢、不稳定,还可能因环境差异失败。
- 用
raise ValueError("invalid input")直接抛异常,干净可控 - 配合
with self.assertRaises(ValueError):或pytest.raises(ValueError)断言 - 确保
raise发生在被测试的代码执行路径内,而不是测试函数开头就抛
用 unittest.mock.patch 替换真实函数并让它抛异常
当被测函数内部调用了第三方或不可控模块(如 requests.get、open),就得用 patch 拦截调用,并让 mock 返回异常。
容易踩的坑是 patch 的目标路径写错——必须是“被测试代码里导入该函数的位置”,不是函数定义的位置。
- 例如被测模块是
my_module.py,里面写了import requests,然后调用requests.get(...),那 patch 应该写成@patch("my_module.requests.get") - 设置 mock 行为:
mock_get.side_effect = ConnectionError("timeout") -
side_effect可以是异常类、异常实例,或返回异常的可调用对象
用 pytest.raises 捕获异常并检查属性
比起 assertRaises,pytest.raises 更灵活,能拿到异常实例做进一步断言,比如验证错误信息或属性值。
注意:如果没用 with 语句包裹被测调用,异常会直接冒泡导致测试失败,而不是被捕获。
- 正确写法:
with pytest.raises(ValueError) as exc_info:然后assert "missing" in str(exc_info.value) - 避免只断言异常类型而忽略消息内容,生产环境里往往靠消息区分同类异常
- 如果被测函数本不该抛异常,但你误加了
pytest.raises,测试会 fail 并提示 “DID NOT RAISE”
别在测试里用 try/except 手动捕获再断言
自己写 try...except 去抓异常再用 assert 判断类型,看似可行,实则绕远路且易出错。
问题在于:一旦异常没按预期抛出,测试会静默通过(因为 except 没触发,后续也没断言);或者异常类型不对,却因漏判消息而误报成功。
- 框架提供的
assertRaises/pytest.raises是原子操作:要么捕获到指定异常,要么测试立刻失败 - 手写
try/except还要额外处理else和finally分支,增加认知负担 - 唯一适合手写的场景是验证异常链(
__cause__或__context__),但这种情况极少
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











