Stu*_*Cox 7 python unit-testing assertraises python-unittest
所有断言方法(除了
assertRaises(),assertRaisesRegexp())接受一个msg论点,即,如果指定,则使用作为在发生故障时的错误消息
...但是如果我想为assertRaises()或指定错误消息assertRaisesRegexp()怎么办?
使用案例:在循环中测试各种值时,如果失败,我想知道哪一个:
NON_INTEGERS = [0.21, 1.5, 23.462, math.pi]
class FactorizerTestCase(unittest.TestCase):
def test_exception_raised_for_non_integers(self):
for value in NON_INTEGERS:
with self.assertRaises(ValueError):
factorize(value)
Run Code Online (Sandbox Code Playgroud)
如果其中任何一个失败,我得到:
AssertionError: ValueError not raised
Run Code Online (Sandbox Code Playgroud)
这对我来说找不到哪一个失败并没有太大帮助...如果我能提供msg=像我一样的论据assertEqual()等等!
(我当然可以将它们分解为单独的测试函数 - 但是我可能需要测试一些值,或者它需要一些缓慢/昂贵的设置,或者它是更长时间功能测试的一部分)
我很喜欢它,如果我可以很容易地得到它报告:
AssertionError: ValueError not raised for input 23.462
Run Code Online (Sandbox Code Playgroud)
- 但是要保证重新实现/扩展assertRaises()并在我的测试中添加更多代码也不是一件非常重要的事情.
1.我发现的最简单(但很hacky!)的方法是:
\n\nfor value in NON_INTEGERS:\n with self.assertRaises(ValueError) as cm:\n cm.expected.__name__ = \'ValueError for {}\'.format(value) # custom failure msg\n factorize(value)\nRun Code Online (Sandbox Code Playgroud)\n\n失败时会报告此情况:
\n\nAssertionError: ValueError for 23.462 not raised\nRun Code Online (Sandbox Code Playgroud)\n\n请注意,这仅在使用语法时有效with \xe2\x80\xa6。
它之所以有效,是因为assertRaises()上下文管理器在内部执行此操作:
exc_name = self.expected.__name__\n\xe2\x80\xa6\nraise self.failureException(\n "{0} not raised".format(exc_name))\nRun Code Online (Sandbox Code Playgroud)\n\n因此,如果实现发生变化,可能会很不稳定,尽管 Py3 源代码足够相似,它也应该在那里工作(但不能说我\xe2\x80\x99已经尝试过了)。
\n\n2.不依赖实现的最简单方法是捕获错误并使用改进的消息重新引发它:
\n\nfor value in NON_INTEGERS:\n try:\n with self.assertRaises(ValueError) as cm:\n factorize(value)\n except AssertionError as e:\n raise self.failureException(\'{} for {}\'.format(e.message, value)), sys.exc_info()[2]\nRun Code Online (Sandbox Code Playgroud)\n\n位sys.exc_info()[2]是重用原始的堆栈跟踪,但这种语法仅限于 Py2。这个答案解释了如何为 Py3 执行此操作(并启发了这个解决方案)。
但这已经使测试难以阅读,所以我更喜欢第一个选项。
\n\n\xe2\x80\x98proper\xe2\x80\x99 解决方案需要编写assertRaisesAND_AssertRaisesContext类的包装版本,当您在失败时只需添加一些日志记录时,这听起来有点矫枉过正。