如何在Python2.7的unittest中显示assertRaises()捕获的错误信息?

114 投票
5 回答
103626 浏览
提问于 2025-04-17 09:13

为了确保我的模块中的错误信息能够提供足够的帮助,我想查看所有被assertRaises()捕获的错误信息。现在我每次使用assertRaises()时都这样做,但因为测试代码中有很多这样的调用,实在是太麻烦了。

我该如何打印所有assertRaises()的错误信息呢?我查阅了http://docs.python.org/library/unittest.html的文档,但还是没找到解决办法。我能否通过某种方式修改assertRaises()这个方法?我不想在测试代码中修改所有的assertRaises()行,因为我大多数时候都是按照标准方式使用测试代码。

我想这个问题和Python unittest: 如何测试异常中的参数?有关。

这是我现在的做法。例如:

#!/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)

有什么建议吗?

/Jonas

编辑:

在Robert Rossney的提示下,我成功解决了这个问题。这主要不是为了拼写错误,而是为了确保错误信息对模块的用户来说是有意义的。unittest的正常功能(这也是我大多数时候使用的方式)是通过设置SHOW_ERROR_MESSAGES = False来实现的。

我简单地重写了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

5 个回答

84

你在找的是 assertRaisesRegex,这个方法从 Python 3.2 开始就有了。根据文档的说明:

self.assertRaisesRegex(ValueError, "invalid literal for.*XYZ'$",
                       int, 'XYZ')

或者:

with self.assertRaisesRegex(ValueError, 'literal'):
    int('XYZ')

补充说明:如果你在使用 Python 2.7,那么正确的方法名是 assertRaisesRegexp

177

我以前最喜欢@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)
)
63

默认情况下,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 继承。

不过,实际上,如果你只是担心错误信息拼写错误,并且想为此写测试用例,那么你就不应该把这些信息直接写成字符串。你应该像处理其他重要字符串一样,把它们定义为常量,放在一个模块里,然后导入这个模块,并且要有人负责校对这些内容。一个在代码中拼错单词的开发者,在测试用例中也会拼错。

撰写回答