在Python中使用`assertRaises()`的自定义失败消息?

Stu*_*Cox 7 python unit-testing assertraises python-unittest

Python 2.7版单元测试文档说:

所有断言方法(除了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()并在我的测试中添加更多代码也不是一件非常重要的事情.

Stu*_*Cox 2

1.我发现的最简单(但很hacky!)的方法是:

\n\n
for 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)\n
Run Code Online (Sandbox Code Playgroud)\n\n

失败时会报告此情况:

\n\n
AssertionError: ValueError for 23.462 not raised\n
Run Code Online (Sandbox Code Playgroud)\n\n

请注意,这仅在使用语法时有效with \xe2\x80\xa6

\n\n

它之所以有效,是因为assertRaises()上下文管理器在内部执行此操作:

\n\n
exc_name = self.expected.__name__\n\xe2\x80\xa6\nraise self.failureException(\n    "{0} not raised".format(exc_name))\n
Run Code Online (Sandbox Code Playgroud)\n\n

因此,如果实现发生变化,可能会很不稳定,尽管 Py3 源代码足够相似,它也应该在那里工作(但不能说我\xe2\x80\x99已经尝试过了)。

\n\n

2.不依赖实现的最简单方法是捕获错误并使用改进的消息重新引发它:

\n\n
for 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]\n
Run Code Online (Sandbox Code Playgroud)\n\n

sys.exc_info()[2]是重用原始的堆栈跟踪,但这种语法仅限于 Py2这个答案解释了如何为 Py3 执行此操作(并启发了这个解决方案)。

\n\n

但这已经使测试难以阅读,所以我更喜欢第一个选项。

\n\n

\xe2\x80\x98proper\xe2\x80\x99 解决方案需要编写assertRaisesAND_AssertRaisesContext类的包装版本,当您在失败时只需添加一些日志记录时,这听起来有点矫枉过正。

\n