Python Unit Testing: Automatyczne uruchamianie debuggera, gdy test się nie powiedzie

Czy istnieje sposób na automatyczne uruchomienie debuggera w punkcie, w którym unittest się nie powiedzie?

W tej chwili używam pdb.set_trace () ręcznie, ale jest to bardzo uciążliwe, ponieważ muszę ją dodawać za każdym razem i wyjmować na końcu.

Na Przykład:

import unittest

class tests(unittest.TestCase):

    def setUp(self):
        pass

    def test_trigger_pdb(self):
        #this is the way I do it now
        try:
            assert 1==0
        except AssertionError:
            import pdb
            pdb.set_trace()

    def test_no_trigger(self):
        #this is the way I would like to do it:
        a=1
        b=2
        assert a==b
        #magically, pdb would start here
        #so that I could inspect the values of a and b

if __name__=='__main__':
    #In the documentation the unittest.TestCase has a debug() method
    #but I don't understand how to use it
    #A=tests()
    #A.debug(A)

    unittest.main()
Author: Martijn Pieters, 2010-12-09

6 answers

import unittest
import sys
import pdb
import functools
import traceback
def 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 decorator

class tests(unittest.TestCase):
    @debug_on()
    def test_trigger_pdb(self):
        assert 1 == 0

Poprawiłem kod, aby wywołać post_mortem na wyjątku zamiast set_trace.

 28
Author: Rosh Oxymoron,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-14 19:03:14

Myślę, że to, czego szukasz, to nos . Działa jak biegacz testowy dla unittest .

Możesz wpaść do debuggera w przypadku błędów, za pomocą następującego polecenia:

nosetests --pdb
 34
Author: cmcginty,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-31 00:39:59

Prostą opcją jest po prostu Uruchamianie testów bez zbierania wyników i pozwalanie, aby pierwszy wyjątek spadł ze stosu (dla arbitralnej obsługi post mortem) przez np.

try: unittest.findTestCases(__main__).debug()
except:
    pdb.post_mortem(sys.exc_info()[2])

Inna opcja: Zastąp unittest.TextTestResult'S addError i addFailure w testowym biegaczu debugowania do natychmiastowego debugowania post_mortem (przed tearDown()) - lub do zbierania i obsługi błędów i tracebacków w zaawansowany sposób.

(nie wymaga dodatkowych ram ani dodatkowego dekoratora dla metod badawczych)

Podstawowe przykład:

import unittest, pdb

class TC(unittest.TestCase):
    def testZeroDiv(self):
        1 / 0

def 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()
 4
Author: kxr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-12-30 14:06:31

Zewnętrzne ulepszenia frameworku testowego wydają się na ogół obejmować tę funkcję (nose i nose2 były już wspomniane w innych odpowiedziach). Trochę więcej:

Pytest go wspiera.

pytest --pdb

Lub jeśli używasz absl-py ' S absltest zamiast unittest module:

name_of_test.py --pdb_post_mortem
 2
Author: gps,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-08-27 22:31:36

Aby zastosować odpowiedź@cmcginty do następcy nos 2 (zalecane przez nose dostępne na systemach opartych na Debianie przez apt-get install nose2), możesz wpaść do debugera na awarie i błędy, wywołując

nose2

W katalogu testów.

W tym celu musisz mieć odpowiedni .unittest.cfg w katalogu domowym lub unittest.cfg w katalogu projektu; musi on zawierać linie

[debugger]
always-on = True
errors-only = False
 1
Author: serv-inc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-19 09:06:19

Oto wbudowane, bez dodatkowych modułów rozwiązanie:

import unittest
import sys
import pdb

####################################
def ppdb(e=None):
    """conditional debugging
       use with:  `if ppdb(): pdb.set_trace()` 
    """
    return ppdb.enabled

ppdb.enabled = False
###################################


class SomeTest(unittest.TestCase):

    def test_success(self):
        try:
            pass
        except Exception, e:
            if ppdb(): pdb.set_trace()
            raise

    def test_fail(self):
        try:
            res = 1/0
            #note:  a `nosetests --pdb` run will stop after any exception
            #even one without try/except and ppdb() does not not modify that.
        except Exception, e:
            if ppdb(): pdb.set_trace()
            raise


if __name__ == '__main__':
    #conditional debugging, but not in nosetests
    if "--pdb" in sys.argv:
        print "pdb requested"
        ppdb.enabled = not sys.argv[0].endswith("nosetests")
        sys.argv.remove("--pdb")

    unittest.main()

Zadzwoń z {[1] } i się zatrzyma. W przeciwnym razie nie będzie.

 0
Author: JL Peyret,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-05 18:26:07