Python单元测试:测试失败时自动运行调试器

时间:2010-12-09 13:58:23

标签: python unit-testing pdb python-unittest

有没有办法在单元测试失败时自动启动调试器?

现在我只是手动使用pdb.set_trace(),但这非常繁琐,因为我需要每次添加它并在结束时将其取出。

例如:

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

6 个答案:

答案 0 :(得分:36)

我认为你要找的是nose。它就像unittest的测试运行器一样。

您可以使用以下命令将错误放入调试器:

nosetests --pdb

答案 1 :(得分:23)

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

我更正了代码,在异常而不是set_trace上调用post_mortem。

答案 2 :(得分:3)

一个简单的选择是在没有结果收集的情况下运行测试,并让第一个异常崩溃堆栈(用于任意事后处理),例如。

unittest.TextTestResult

另一个选项:在调试测试运行器中覆盖addError的{​​{1}}和addFailure,以便立即进行post_mortem调试(在tearDown()之前) - 或者用于收集和处理错误和放大器;以先进的方式追溯。

(不需要额外的框架或测试方法的额外装饰器)

基本示例:

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

答案 3 :(得分:0)

要通过apt-get install nose2@cmcginty's answer应用于基于Debian的系统上的后继nose 2recommended by nose),您可以drop into the debugger查看有关失败和错误的信息。调用

nose2

在您的测试目录中。

为此,您需要在主目录中有一个合适的.unittest.cfg或在项目目录中有unittest.cfg;它需要包含行

[debugger]
always-on = True
errors-only = False

答案 4 :(得分:0)

这是一个内置的,没有额外模块的解决方案:

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

python myunittest.py --pdb调用它,它将停止。否则就不会。

答案 5 :(得分:0)

第三方测试框架的增强通常似乎包含此功能(其他答案中已经提到了nosenose2)。一些:

pytest支持。

pytest --pdb

或者,如果您使用absl-pyabsltest而不是unittest模块:

name_of_test.py --pdb_post_mortem