assertraises最稳妥方式是传函数名和参数(不加括号);需验消息或属性时用with上下文获取cm.exception;它不捕获systemexit等baseexception;无assertnotraises,应显式try/except+self.fail()。

用 assertRaises 捕获并验证异常类型
直接断言函数是否抛出指定异常,是最常用也最稳妥的方式。它会执行被测代码,自动捕获异常,并检查类型(和可选的参数)是否匹配。
常见错误是把带括号的函数调用传给 assertRaises,比如 self.assertRaises(ValueError, func()) —— 这会导致函数**立即执行**,异常在断言前就抛出了,测试直接失败。
- 正确写法:传函数名 + 参数(不加括号),让
assertRaises自己调用:self.assertRaises(ValueError, func, "bad_input") - 如果需要检查异常消息,用上下文管理器形式更清晰:
with self.assertRaises(ValueError) as cm: func("bad_input") self.assertEqual(str(cm.exception), "invalid value") - 注意:
assertRaises默认只匹配异常类型,不校验消息内容;消息需额外取cm.exception手动比对
当异常带多个参数或自定义属性时,用上下文管理器取 exception
有些异常(如 ValueError、自定义异常)构造时传了多个参数,或设置了额外属性(如 err.code),仅靠类型断言不够。
快速生成专业的 Python 脚本和应用代码。一键创建完整项目结构,支持CLI、API、爬虫、Bot、Django等多种项目类型,包含完整的项目结构、配置文件、依赖管理、测试、README和文档。
- 必须用
with self.assertRaises(...)形式,才能拿到异常实例cm.exception - 可以访问
args元组:self.assertIn("timeout", cm.exception.args[0]) - 可检查自定义字段:
self.assertEqual(cm.exception.code, 400) - 避免直接打印
cm.exception做字符串匹配——容易因空格、换行、本地化消息导致不稳定
assertRaises 不捕获 BaseException 及其子类(如 SystemExit、KeyboardInterrupt)
unittest 的 assertRaises 默认只处理继承自 Exception 的异常,而 SystemExit、KeyboardInterrupt 是 BaseException 的直系子类,会被跳过。
- 若测试中调用了
sys.exit()或exit(),assertRaises(SystemExit)会静默失败(测试通过但实际没捕获) - 解决方法:改用
self.assertRaisesRegex(SystemExit, ".*")(Python 3.3+)或手动 patchsys.exit - 更推荐方式:用
unittest.mock.patch替换sys.exit,验证是否被调用及参数:mock_exit.assert_called_once_with(1)
测试“不应抛异常”的场景,别漏掉 assertNotRaises 的替代方案
unittest 没有内置 assertNotRaises,但常有人误以为“不写 assertRaises 就代表没异常”——这是错的。未捕获的异常会让测试直接报 ERROR,而非 FAIL,容易被忽略。
- 明确表达“此处不该抛异常”,可用空的
try/except+self.fail():try: result = good_func(42) except ValueError: self.fail("good_func raised ValueError unexpectedly") - 或者用
assertRaises的反向逻辑:捕获所有Exception并 fail,但通常没必要——只要测试本身不崩溃,就说明没抛出未处理异常 - 真正关键的是:确保测试运行环境干净,比如 mock 掉可能触发异常的外部依赖,否则“没异常”可能是偶然
BaseException 类异常的特殊处理,以及“不抛异常”这个预期的显式表达。这些地方不细想,测试看似通过,实则掩盖了真实问题。Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










