我们如何测试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)

