我们如何测试Python函数引发异常?
时间:2020-03-06 14:41:10 来源:igfitidea点击:
如何编写仅在函数未引发预期异常的情况下才会失败的单元测试?
解决方案
看一看unittest模块的assertRaises方法。
使用unittest模块中的TestCase.assertRaises
(或者TestCase.failUnlessRaises
),例如:
import mymod class MyTestCase(unittest.TestCase): def test1(self): self.assertRaises(SomeCoolException, mymod.myfunc)
代码应遵循以下模式(这是一个unittest模块样式测试):
def test_afunction_throws_exception(self): try: afunction() except ExpectedException: pass except Exception as e: self.fail('Unexpected exception raised:', e) else: self.fail('ExpectedException not raised')
在Python <2.7上,此构造对于检查预期异常中的特定值很有用。 unittest函数" assertRaises"仅检查是否引发了异常。
我上一个答案中的代码可以简化为:
def test_afunction_throws_exception(self): self.assertRaises(ExpectedException, afunction)
如果函数接受参数,则将其传递给assertRaises,如下所示:
def test_afunction_throws_exception(self): self.assertRaises(ExpectedException, afunction, arg1, arg2)
我几乎在所有地方都使用doctest [1],因为我喜欢同时记录和测试函数的事实。
看一下这段代码:
def throw_up(something, gowrong=False): """ >>> throw_up('Fish n Chips') Traceback (most recent call last): ... Exception: Fish n Chips >>> throw_up('Fish n Chips', gowrong=True) 'I feel fine!' """ if gowrong: return "I feel fine!" raise Exception(something) if __name__ == '__main__': import doctest doctest.testmod()
如果将此示例放在模块中并从命令行运行它,则将评估和检查两个测试用例。
[1] Python文档:23.2 doctest-测试交互式Python示例
我刚刚发现Mock库提供了assertRaisesWithMessage()方法(在其unittest.TestCase子类中),该方法不仅会检查是否引发了预期的异常,还检查了与预期消息一起引发的异常:
from testcase import TestCase import mymod class MyTestCase(TestCase): def test1(self): self.assertRaisesWithMessage(SomeCoolException, 'expected message', mymod.myfunc)
从Python 2.7开始,我们可以使用上下文管理器来获取抛出的实际Exception对象:
import unittest def broken_function(): raise Exception('This is broken') class MyTestCase(unittest.TestCase): def test(self): with self.assertRaises(Exception) as context: broken_function() self.assertTrue('This is broken' in context.exception) if __name__ == '__main__': unittest.main()
http://docs.python.org/dev/library/unittest.html#unittest.TestCase.assertRaises
在Python 3.5中,我们必须将context.exception
包裹在str
中,否则会得到TypeError
。
self.assertTrue('This is broken' in str(context.exception))
我们可以使用unittest模块中的assertRaises
import unittest class TestClass(): def raises_exception(self): raise Exception("test") class MyTestCase(unittest.TestCase): def test_if_method_raises_correct_exception(self): test_class = TestClass() # note that you dont use () when passing the method to assertRaises self.assertRaises(Exception, test_class.raises_exception)