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



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)

相关内容

  • 没有找到相关文章

最新更新