Python Unit Testing: Automatically Running the Debugger when a test fails
import unittestimport sysimport pdbimport functoolsimport tracebackdef debug_on(*exceptions): if not exceptions: exceptions = (AssertionError, ) def decorator(f): @functools.wraps(f) def wrapper(*args, **kwargs): try: return f(*args, **kwargs) except exceptions: info = sys.exc_info() traceback.print_exception(*info) pdb.post_mortem(info[2]) return wrapper return decoratorclass tests(unittest.TestCase): @debug_on() def test_trigger_pdb(self): assert 1 == 0
I corrected the code to call post_mortem on the exception instead of set_trace.
A simple option is to just run the tests without result collection and letting the first exception crash down the stack (for arbitrary post mortem handling) by e.g.
try: unittest.findTestCases(__main__).debug()except: pdb.post_mortem(sys.exc_info()[2])
Another option: Override unittest.TextTestResult
's addError
and addFailure
in a debug test runner for immediate post_mortem debugging (before tearDown()
) - or for collecting and handling errors & tracebacks in an advanced way.
(Doesn't require extra frameworks or an extra decorator for test methods)
Basic example:
import unittest, pdbclass TC(unittest.TestCase): def testZeroDiv(self): 1 / 0def debugTestRunner(post_mortem=None): """unittest runner doing post mortem debugging on failing tests""" if post_mortem is None: post_mortem = pdb.post_mortem class DebugTestResult(unittest.TextTestResult): def addError(self, test, err): # called before tearDown() traceback.print_exception(*err) post_mortem(err[2]) super(DebugTestResult, self).addError(test, err) def addFailure(self, test, err): traceback.print_exception(*err) post_mortem(err[2]) super(DebugTestResult, self).addFailure(test, err) return unittest.TextTestRunner(resultclass=DebugTestResult)if __name__ == '__main__': ##unittest.main() unittest.main(testRunner=debugTestRunner()) ##unittest.main(testRunner=debugTestRunner(pywin.debugger.post_mortem)) ##unittest.findTestCases(__main__).debug()