我正在尝试为Continuing in Python's unittest when an assertion fails实现一个明确的答案。
我希望改进投票率最高且未被接受的答案:https://stackoverflow.com/a/5028110/4934640
我有这个答案的问题是,它迫使我在单元测试中使用try...catch
。然后,我试图将try...catch
逻辑封装在TestCase.assertEqual
方法的替代中。
到目前为止,太好了。我设法覆盖TestCase.assertEqual
方法,但是,显示的stacktrace错误。
运行以下最小示例:
import unittest
import traceback
class MultipleAssertionFailures(unittest.TestCase):
def __init__(self, *args, **kwargs):
self.verificationErrors = []
super(MultipleAssertionFailures, self).__init__( *args, **kwargs )
def tearDown(self):
super(MultipleAssertionFailures, self).tearDown()
if self.verificationErrors:
self.fail( '\n\n' + '\n'.join( self.verificationErrors ) )
self.verificationErrors.clear()
def assertEqual(self, goal, results, msg=""):
try:
super( MultipleAssertionFailures, self ).assertEqual( goal, results, msg )
except unittest.TestCase.failureException as error:
stacktrace = traceback.format_exc()
# stacktrace = traceback.format_stack()
self.verificationErrors.append( "".join( stacktrace ) )
# class DummyTestCase(unittest.TestCase):
class DummyTestCase(MultipleAssertionFailures):
def setUp(self):
self.maxDiff = None
super(DummyTestCase, self).setUp()
def tearDown(self):
super(DummyTestCase, self).tearDown()
def test_function_name(self):
self.assertEqual( "var", "bar" )
self.assertEqual( "1937", "511" )
if __name__ == '__main__':
unittest.main()
您得到以下输出:
F
======================================================================
FAIL: test_function_name (__main__.DummyTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "D:\User\Downloads\test.py", line 36, in tearDown
super(DummyTestCase, self).tearDown()
File "D:\User\Downloads\test.py", line 15, in tearDown
self.fail( '\n\n' + '\n'.join( self.verificationErrors ) )
AssertionError:
Traceback (most recent call last):
File "D:\User\Downloads\test.py", line 21, in assertEqual
super( MultipleAssertionFailures, self ).assertEqual( goal, results, msg )
File "F:\Python\lib\unittest\case.py", line 844, in assertEqual
assertion_func(first, second, msg=msg)
File "F:\Python\lib\unittest\case.py", line 1228, in assertMultiLineEqual
self.fail(self._formatMessage(msg, standardMsg))
File "F:\Python\lib\unittest\case.py", line 685, in fail
raise self.failureException(msg)
AssertionError: 'var' != 'bar'
- var
? ^
+ bar
? ^
:
Traceback (most recent call last):
File "D:\User\Downloads\test.py", line 21, in assertEqual
super( MultipleAssertionFailures, self ).assertEqual( goal, results, msg )
File "F:\Python\lib\unittest\case.py", line 844, in assertEqual
assertion_func(first, second, msg=msg)
File "F:\Python\lib\unittest\case.py", line 1228, in assertMultiLineEqual
self.fail(self._formatMessage(msg, standardMsg))
File "F:\Python\lib\unittest\case.py", line 685, in fail
raise self.failureException(msg)
AssertionError: '1937' != '511'
- 1937
+ 511
:
在输出上,您将注意到两个显示的堆栈跟踪是错误的,因为它们不反映单元测试代码的位置,而仅反映我的断言代码打开的位置。通过在最小的示例上注释class DummyTestCase(MultipleAssertionFailures)
并取消注释class DummyTestCase(unittest.TestCase)
,您将看到stacktrace的正确输出应为:
F
======================================================================
FAIL: test_function_name (__main__.DummyTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "D:\User\Downloads\test.py", line 39, in test_function_name
self.assertEqual( "var", "bar" )
AssertionError: 'var' != 'bar'
- var
? ^
+ bar
? ^
此堆栈跟踪(内置跟踪)正确指向test.py", line 39, in test_function_name
。我尝试查看TestCase
module,但无法弄清楚它是如何产生有意义的堆栈跟踪的。
或者,取消注释行stacktrace = traceback.format_exc()
,我们可以获得真正完整的堆栈跟踪:
F
======================================================================
FAIL: test_function_name (__main__.DummyTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "D:\User\Downloads\test.py", line 36, in tearDown
super(DummyTestCase, self).tearDown()
File "D:\User\Downloads\test.py", line 15, in tearDown
self.fail( '\n\n' + '\n'.join( self.verificationErrors ) )
AssertionError:
File "D:\User\Downloads\test.py", line 43, in <module>
unittest.main()
File "F:\Python\lib\unittest\main.py", line 101, in __init__
self.runTests()
File "F:\Python\lib\unittest\main.py", line 271, in runTests
self.result = testRunner.run(self.test)
File "F:\Python\lib\unittest\runner.py", line 176, in run
test(result)
File "F:\Python\lib\unittest\suite.py", line 84, in __call__
return self.run(*args, **kwds)
File "F:\Python\lib\unittest\suite.py", line 122, in run
test(result)
File "F:\Python\lib\unittest\suite.py", line 84, in __call__
return self.run(*args, **kwds)
File "F:\Python\lib\unittest\suite.py", line 122, in run
test(result)
File "F:\Python\lib\unittest\case.py", line 668, in __call__
return self.run(*args, **kwds)
File "F:\Python\lib\unittest\case.py", line 620, in run
testMethod()
File "D:\User\Downloads\test.py", line 39, in test_function_name
self.assertEqual( "var", "bar" )
File "D:\User\Downloads\test.py", line 25, in assertEqual
stacktrace = traceback.format_stack()
File "D:\User\Downloads\test.py", line 43, in <module>
unittest.main()
File "F:\Python\lib\unittest\main.py", line 101, in __init__
self.runTests()
File "F:\Python\lib\unittest\main.py", line 271, in runTests
self.result = testRunner.run(self.test)
File "F:\Python\lib\unittest\runner.py", line 176, in run
test(result)
File "F:\Python\lib\unittest\suite.py", line 84, in __call__
return self.run(*args, **kwds)
File "F:\Python\lib\unittest\suite.py", line 122, in run
test(result)
File "F:\Python\lib\unittest\suite.py", line 84, in __call__
return self.run(*args, **kwds)
File "F:\Python\lib\unittest\suite.py", line 122, in run
test(result)
File "F:\Python\lib\unittest\case.py", line 668, in __call__
return self.run(*args, **kwds)
File "F:\Python\lib\unittest\case.py", line 620, in run
testMethod()
File "D:\User\Downloads\test.py", line 40, in test_function_name
self.assertEqual( "1937", "511" )
File "D:\User\Downloads\test.py", line 25, in assertEqual
stacktrace = traceback.format_stack()
我怎么总是像完整的TestCase.assertEqual
那样将整个堆栈跟踪都切分成有意义的东西?