Python Unit Testing: Automatically Running the Debugger when a test fails Python Unit Testing: Automatically Running the Debugger when a test fails python python

Python Unit Testing: Automatically Running the Debugger when a test fails


I think what you are looking for is nose. It works like a test runner for unittest.

You can drop into the debugger on errors, with the following command:

nosetests --pdb


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()