Я пытаюсь реализовать чистый ответ для Продолжаем в модульном тесте Python, когда утверждение не удается .
Я хотел бы улучшить ответ, получивший наибольшее количество голосов и не принятый: https://stackoverflow.com/a/5028110/4934640
Проблема, на которую я отвечаю, состоит в том, что она заставляет меня использовать try...catch
в моих модульных тестах.Затем я пытаюсь инкапсулировать логику try...catch
в переопределение метода TestCase.assertEqual
.
Пока все хорошо.Мне удается переопределить метод TestCase.assertEqual
, однако представленная трассировка стека неверна.
Выполнение следующего минимального примера:
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)
в минимальном примере, вы увидите, как правильно должен быть вывод трассировки стека:
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
, но не смог понять, как ему удалось создать эту значимую трассировку стека.
В качестве альтернативы, раскомментировав строку 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
делает?