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

Python单元测试:测试失败时自动运行调试器,python,unit-testing,pdb,python-unittest,Python,Unit Testing,Pdb,Python Unittest,有没有办法在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:

有没有办法在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()

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

我想您要查找的是。它的工作原理就像一个测试跑步者

您可以使用以下命令在出现错误时进入调试器:

nosetests --pdb
要应用于后续系统(可通过
apt get install nose2
在基于Debian的系统上获得),您可以通过调用

nose2
在您的测试目录中

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

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

一个简单的选择是只运行测试而不收集结果,并让第一个异常在堆栈中崩溃(用于任意事后处理)


另一个选项:在调试测试运行程序中覆盖
unittest.TextTestResult
addError
addFailure
,以便立即进行事后调试(在
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()

这是一个内置的、无需额外模块的解决方案:

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调用它,它将停止。否则就不会了。

第三方测试框架增强通常似乎包括该功能(
nose
nos2
在其他答案中已经提到)。还有:

支持它

pytest --pdb
或者如果您使用的是's
absltest
而不是
unittest
模块:

name_of_test.py --pdb_post_mortem

我还建议您使用全局标志来打开和关闭此调试。这将使运行测试更加复杂。如果我运行某人的测试套件,它弹出调试器,我会非常生气。罗斯,谢谢。它工作得很好。关于全局标志,这是一个很好的解决方案,所以+1。我想在你的代码中添加以下内容:导入pdb;导入系统;在pdb.验尸(…)后,提高。这是应该重新抛出异常的罕见情况。如果用户继续一个失败的测试用例,否则它将被视为通过。另一方面;如果能够检测到pdb已经在运行,而不弹出unittests的调试器,但在调试器下启动时出现故障,我会更高兴。@Heathunnicutt:听起来可能有一种方法可以检测调试器是否已经在运行,请参阅问题。如果要使用
self.assertEquals
而不是普通的
assert
,以便测试具有“失败”而不是“错误”,那么要运行的命令将是
nosetest--pdb failures
。在win32上,使用python 2.7,我用
easy\u install nose
安装了nose,但后来发现命令是nosetests而不是nosetest。在Ubuntu上,我还发现这个很棒的命令名为“nosetests”,最后强调复数“s”。您可以安装python nose包(sudo apt get install python nose)来获得这个方便的命令。要运行现有测试,“nosetests--pdb failures./test_set.py”,其中test_set.py是您现有的单元测试。对于成功者nose2,请参阅下面的答案。由于nose未维护,因此被否决(请参阅nose2)。这是否需要是unittest.findTestCases('main').debug()?
pytest --pdb
name_of_test.py --pdb_post_mortem