Python 2.7 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)
如果其中任何一个失败,我会得到:
AssertionError: ValueError not raised
这对我来说对找出哪个失败没有太大帮助......如果我能像assertEqual()
等一样提供一个msg=
论据就好了!
(我当然可以将它们分解为单独的测试函数 - 但也许我想要测试大量值,或者它需要一些缓慢/昂贵的设置,或者它是较长功能测试的一部分)
如果我能轻松让它报告以下内容,我会很高兴:
AssertionError: ValueError not raised for input 23.462
— 但这也不是一件足够关键的事情,无法保证重新实现/扩展assertRaises()
并向我的测试添加加载更多代码。
你也可以回退到使用self.fail
,这感觉很烦人,但我认为看起来不那么笨拙
for value in NON_INTEGERS:
with self.assertRaises(ValueError) as cm:
factorize(value)
self.fail('ValueError not raised for {}'.format(value))
1. 我发现的最简单(但很笨拙!)的方法是:
for value in NON_INTEGERS:
with self.assertRaises(ValueError) as cm:
cm.expected.__name__ = 'ValueError for {}'.format(value) # custom failure msg
factorize(value)
这将在失败时报告此问题:
AssertionError: ValueError for 23.462 not raised
请注意,这仅在使用with …
语法时有效。
它之所以有效,是因为assertRaises()
上下文管理器在内部执行此操作:
exc_name = self.expected.__name__
…
raise self.failureException(
"{0} not raised".format(exc_name))
所以如果实现发生变化,可能会很不稳定,尽管 Py3 源代码足够相似,它也应该在那里工作(但不能说我已经尝试过)。
2. 不依赖实现的最简单方法是捕获错误并使用改进的消息重新引发它:
for value in NON_INTEGERS:
try:
with self.assertRaises(ValueError) as cm:
factorize(value)
except AssertionError as e:
raise self.failureException('{} for {}'.format(e.message, value)), sys.exc_info()[2]
sys.exc_info()[2]
位是重用原始堆栈跟踪,但此语法仅是 Py2。这个答案解释了如何为 Py3 执行此操作(并启发了这个解决方案)。
但这已经使测试难以阅读,所以我更喜欢第一个选项。
"正确"的解决方案需要编写assertRaises
和_AssertRaisesContext
类的包装版本,这听起来有点矫枉过正,因为您可以在失败时加入一些日志记录。
我用这个代替assertRaises
:
def test_empty_username(self):
# noinspection PyBroadException
try:
my_func(username="")
except Exception:
# If it does, we are OK.
return
# If not, we are here.
self.fail("my_func() must reject empty username.")
在 Python 3 中,unittest
现在将错误消息公开为您从with self.assertRaises()
获得的_AssertRaisesContext
实例的适当、可公开访问的属性。所以在 Python 3 中,你可以这样做:
with self.assertRaises(ValueError) as assertion:
assertion.msg = f"ValueError not raised for input {value}"
factorize(value)