运行Python unittest以便在成功时不打印任何内容,只有AssertionError()如果失败

时间:2011-08-24 19:28:40

标签: python unit-testing

我有一个标准unittest格式的测试模块

class my_test(unittest.TestCase):

    def test_1(self):
        [tests]

    def test_2(self):
        [tests]
  etc....

我的公司有一个专有的测试工具,它将我的模块作为命令行脚本执行,它将捕获我的模块引发的任何错误,但要求我的模块在成功时静音。

所以,我试图找到一种方法来裸露运行我的测试模块,这样如果我的所有测试都通过,那么屏幕上什么都没有打印出来,如果测试因AssertionError而失败,那么该错误会通过标准传递Python错误堆栈(就像普通Python脚本中的任何其他错误一样。)

使用unittest.main()函数的docs拥护者在给定模块中运行所有测试,如

if __name__ == "__main__":
    unittest.main()

问题在于,这将测试结果包含在unittest的线束中,因此即使所有测试都成功,它仍然会在屏幕上打印出一些绒毛,如果有错误,它不会被简单地转储为通常的python错误,还穿着马具。

我尝试使用

将输出重定向到备用流
with open('.LOG','a') as logf:
    suite = unittest.TestLoader().loadTestsFromTestCase(my_test)
    unittest.TextTestRunner(stream = logf).run(suite)

这里的问题是EVERYTHING被传送到日志文件(包括所有错误通知)。因此,当我的公司利用运行该模块时,它就会成功完成,因为就其所知,没有引发任何错误(因为它们都是通过管道传输到日志文件中)。

关于如何构建一个能够抑制所有漏洞的测试运行器以及通过正常Python错误堆栈管道错误的任何建议?与往常一样,如果您认为有更好的方法来解决这个问题,请告诉我。

编辑:

以下是我最终用来解决此问题的方法。首先,我在我的测试类中添加了一个“get_test_names()”方法:

class my_test(unittest.TestCase):
  etc....
    @staticmethod
    def get_test_names():
        """Return the names of all the test methods for this class."""
        test_names = [ member[0] for memeber in inspect.getmembers(my_test)
                       if 'test_' in member[0] ]

然后我用以下内容将我的电话换成了unittest.main()

# Unittest catches all errors raised by the test cases, and returns them as 
# formatted strings inside a TestResult object. In order for the test 
# harness to catch these errors they need to be re-raised, and so I am defining 
# this CompareError class to do that. 
# For each code error, a CompareError will be raised, with the original error 
# stack as the argument. For test failures (i.e. assertion errors) an 
# AssertionError is raised.
class CompareError(Exception):
    def __init__(self,err):
        self.err = err
    def __str__(self):
        return repr(self.err)

# Collect all tests into a TestSuite()
all_tests = ut.TestSuite()
for test in my_test.get_test_names():
    all_tests.addTest(my_test(test))
# Define a TestResult object and run tests
results = ut.TestResult()
all_tests.run(results)
# Re-raise any script errors
for error in results.errors:
    raise CompareError(error[1])
# Re-raise any test failures 
for failure in results.failures:
    raise AssertionError(failure[1])

1 个答案:

答案 0 :(得分:3)

我想出了这个。如果您能够更改命令行,则可以删除内部io重定向。

import sys, inspect, traceback

# redirect stdout,
# can be replaced by testharness.py > /dev/null at console
class devnull():
    def write(self, data):
        pass

f = devnull()
orig_stdout = sys.stdout
sys.stdout = f

class TestCase():
    def test_1(self):
        print 'test_1'

    def test_2(self):
        raise AssertionError, 'test_2'

    def test_3(self):
        print 'test_3'


if __name__ == "__main__":
    testcase = TestCase()
    testnames =  [ t[0] for t in inspect.getmembers(TestCase)
                        if t[0].startswith('test_') ]

    for testname in testnames:
        try:
            getattr(testcase, testname)()
        except AssertionError, e:
            print >> sys.stderr, traceback.format_exc()

# restore
sys.stdout = orig_stdout