为什么Python unittest的assertRaises方法无法捕获已抛出的异常?
问题根因
- 你的
tuple_unpacker内部通过try-except捕获了ValueError和TypeError后,仅打印了提示信息,没有将异常重新抛出到函数外部。unittest的assertRaises只能捕获从被测函数向外抛出的未处理异常,自然会判定异常未抛出,第一次测试失败就是这个原因。 - 第二种写法属于语法错误:
assertRaises的标准入参规则是assertRaises(异常类型, 可调用对象, 入参1, 入参2...),你直接写func((1,'a',1))是先执行了函数,把异常分支返回的None传给了assertRaises,框架尝试调用None对象时抛出了TypeError,属于误打误撞匹配到了你要断言的异常,完全不符合测试逻辑;到第二个断言时框架抛出的TypeError和你要校验的ValueError不匹配,就触发了报错。
解决方案
根据你的业务需求选其中一种即可:
场景1:保留函数内部吞掉异常、只打印提示的逻辑
不需要用assertRaises,改为校验函数的返回值和打印输出即可,示例代码:
import unittest from io import StringIO import sys class TestInner(unittest.TestCase): def test_tuple_unpacker(self): func = outer() # 捕获标准输出校验打印内容 saved_stdout = sys.stdout try: sys.stdout = captured_output = StringIO() res1 = func((1,'a',1)) self.assertEqual(captured_output.getvalue().strip(), 'pass only integers in tuple') self.assertIsNone(res1) sys.stdout = captured_output2 = StringIO() res2 = func((1,1,1,1)) self.assertEqual(captured_output2.getvalue().strip(), 'pass tuple with exactly 3 elements') self.assertIsNone(res2) # 正常逻辑校验 self.assertEqual(func((1,2,3)), 6) finally: sys.stdout = saved_stdout
场景2:需要函数打印提示后仍向外抛出异常,支持assertRaises校验
先修改原函数的异常分支,打印后加raise重新抛出异常:
def outer(): def tuple_unpacker( mytuple ): try: a,b,c = mytuple return a+b+c except ValueError: print('pass tuple with exactly 3 elements') raise except TypeError: print('pass only integers in tuple') raise return tuple_unpacker
测试代码用标准assertRaises语法即可,更推荐用上下文管理器写法避免参数传递错误:
class TestInner(unittest.TestCase): def test_tuple_unpacker(self): func = outer() # 上下文管理器写法更易读,不易出错 with self.assertRaises(TypeError): func((1,'a',1)) with self.assertRaises(ValueError): func((1,1,1,1))
内容的提问来源于stack exchange,提问作者mn65
相关产品推荐
相关产品推荐

