为了确保来自我的模块的错误消息提供信息,我希望看到assertRaises()捕获的所有错误消息。今天我为每个assertRaises()执行此操作,但由于测试代码中有很多这样的内容,因此非常繁琐。
如何打印所有assertRaises()的错误消息?我已经研究了http://docs.python.org/library/unittest.html上的文档而没有弄清楚如何解决它。我可以以某种方式monkeypatch assertRaises()方法?我不想更改测试代码中的所有assertRaises()行,因为我经常以标准方式使用测试代码。
我猜这个问题与Python unittest: how do I test the argument in an Exceptions?
有关今天我就是这样做的。例如:
#!/usr/bin/env python
def fail():
raise ValueError('Misspellled errrorr messageee')
测试代码:
#!/usr/bin/env python
import unittest
import failure
class TestFailureModule(unittest.TestCase):
def testFail(self):
self.assertRaises(ValueError, failure.fail)
if __name__ == '__main__':
unittest.main()
要检查错误消息,我只需将assertRaises()中的错误类型更改为例如IOError。然后我可以看到错误消息:
E
======================================================================
ERROR: testFail (__main__.TestFailureModule)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_failure.py", line 8, in testFail
self.assertRaises(IOError, failure.fail)
File "/usr/lib/python2.7/unittest/case.py", line 471, in assertRaises
callableObj(*args, **kwargs)
File "/home/jonas/Skrivbord/failure.py", line 4, in fail
raise ValueError('Misspellled errrorr messageee')
ValueError: Misspellled errrorr messageee
----------------------------------------------------------------------
Ran 1 test in 0.001s
FAILED (errors=1)
有什么建议吗? /乔纳斯
修改
借助Robert Rossney的提示,我设法解决了这个问题。它主要不是用于拼写错误,而是用于确保错误消息对模块用户真正有意义。通过设置SHOW_ERROR_MESSAGES = False来实现unittest的正常功能(这是我大多数时间使用它的方式)。
我只是覆盖了assertRaises()方法,如下所示。它就像魅力一样!
SHOW_ERROR_MESSAGES = True
class NonexistantError(Exception):
pass
class ExtendedTestCase(unittest.TestCase):
def assertRaises(self, excClass, callableObj, *args, **kwargs):
if SHOW_ERROR_MESSAGES:
excClass = NonexistantError
try:
unittest.TestCase.assertRaises(self, excClass, callableObj, *args, **kwargs)
except:
print '\n ' + repr(sys.exc_info()[1])
结果输出的一小部分:
testNotIntegerInput (__main__.TestCheckRegisteraddress) ...
TypeError('The registeraddress must be an integer. Given: 1.0',)
TypeError("The registeraddress must be an integer. Given: '1'",)
TypeError('The registeraddress must be an integer. Given: [1]',)
TypeError('The registeraddress must be an integer. Given: None',)
ok
testCorrectNumberOfBytes (__main__.TestCheckResponseNumberOfBytes) ... ok
testInconsistentLimits (__main__.TestCheckNumerical) ...
ValueError('The maxvalue must not be smaller than minvalue. Given: 45 and 47, respectively.',)
ValueError('The maxvalue must not be smaller than minvalue. Given: 45.0 and 47.0, respectively.',)
ok
testWrongValues (__main__.TestCheckRegisteraddress) ...
ValueError('The registeraddress is too small: -1, but minimum value is 0.',)
ValueError('The registeraddress is too large: 65536, but maximum value is 65535.',)
ok
testTooShortString (__main__.TestCheckResponseWriteData) ...
ValueError("The payload is too short: 2, but minimum value is 4. Given: '\\x00X'",)
ValueError("The payload is too short: 0, but minimum value is 4. Given: ''",)
ValueError("The writedata is too short: 1, but minimum value is 2. Given: 'X'",)
ValueError("The writedata is too short: 0, but minimum value is 2. Given: ''",)
ok
testKnownValues (__main__.TestCreateBitPattern) ... ok
testNotIntegerInput (__main__.TestCheckSlaveaddress) ...
TypeError('The slaveaddress must be an integer. Given: 1.0',)
TypeError("The slaveaddress must be an integer. Given: '1'",)
TypeError('The slaveaddress must be an integer. Given: [1]',)
TypeError('The slaveaddress must be an integer. Given: None',)
ok
答案 0 :(得分:98)
我曾经更喜欢@Robert Rossney给出的最优秀答案。如今,我更喜欢使用assertRaises作为上下文管理器(unittest2中的新功能),如下所示:
with self.assertRaises(TypeError) as cm:
failure.fail()
self.assertEqual(
'The registeraddress must be an integer. Given: 1.0',
str(cm.exception)
)
答案 1 :(得分:46)
您正在寻找assertRaisesRegexp,这是自Python 2.7以来可用的。来自文档:
self.assertRaisesRegexp(ValueError, 'invalid literal for.*XYZ$', int, 'XYZ')
或:
with self.assertRaisesRegexp(ValueError, 'literal'):
int('XYZ')
答案 2 :(得分:41)
开箱即用的unittest
不会这样做。如果这是你想要经常做的事情,你可以尝试这样的事情:
class ExtendedTestCase(unittest.TestCase):
def assertRaisesWithMessage(self, msg, func, *args, **kwargs):
try:
func(*args, **kwargs)
self.assertFail()
except Exception as inst:
self.assertEqual(inst.message, msg)
从ExtendedTestCase
而不是unittest.TestCase
派生您的单元测试类。
但实际上,如果您只是担心拼写错误的错误消息,并且想要围绕它构建测试用例,则不应该将消息内联为字符串文字。您应该使用它们对任何其他重要字符串执行的操作:将它们定义为导入的模块中的常量,并且某人负责校对。在他的代码中拼错单词的开发人员也会在他的测试用例中拼错它们。
答案 3 :(得分:17)
如果您希望错误消息与某些内容完全匹配:
with self.assertRaises(ValueError) as error:
do_something()
self.assertEqual(error.exception.message, 'error message')
答案 4 :(得分:5)
mkelley33给出了很好的答案,但是这种方法可以被Codacy等代码分析工具检测为问题。问题是它不知道assertRaises
可以用作上下文管理器,并且它报告并非所有参数都传递给assertRaises
方法。
所以,我想改进罗伯特的罗斯尼答案:
class TestCaseMixin(object):
def assertRaisesWithMessage(self, exception_type, message, func, *args, **kwargs):
try:
func(*args, **kwargs)
except exception_type as e:
self.assertEqual(e.args[0], message)
else:
self.fail('"{0}" was expected to throw "{1}" exception'
.format(func.__name__, exception_type.__name__))
主要区别是:
e.args[0]
,因为Py3中的错误没有
message
属性)。