2014-09-25 32 views
1

我正在使用Python的(3.4.1)unittest模块进行单元测试。Python 3 unittest:如何提取测试结果?

我使用进口加载所有我的测试模块文件,然后运行unittest.main():

import unittest 
import testing_module1 
import testing_module2 
# [...] 
if __name__ == '__main__': 
    unittest.main() 

这工作完全适合我,因为它是简单的,并尊重我用来控制冗长的命令行参数或哪些测试运行。

我想继续输出相同的信息,但我想从结果中生成一个XML文件。我试过xmlrunner(https://github.com/xmlrunner/unittest-xml-reporting/)但是:

  • 它不会像标准运行器那样向stdout输出尽可能多的信息;
  • 它使用特定格式的XML,不适合我。

我想用我需要的格式生成XML(我不介意手动操作),但对测试的运行方式做了最小的更改。

我有什么选择?

  1. 我可以编写自己的TestRunner,但我不想重写所有内容,我只是想用最少的代码更改将额外的输出添加到实际运行程序中。
  2. 我可以继承unittest.TextTestRunner,但我担心向它添加XML输出将需要重写每一个方法,首先会丧失继承的优势。
  3. 我可以尝试在拨打unittest.main()之后提取测试结果并解析它。这里的问题在于,unittest.main()似乎在完成后退出,因此它后面的任何代码都未执行。

有什么建议吗?

谢谢!

回答

0

这是如何工作的。在StringIO中捕获到unit.stderr的unittest的输出。在unittest.main后面加入`exit = False'继续。根据需要阅读捕获的输出和处理过程。概念证明:

import contextlib 
import io 
import sys 
import unittest 

class Mytest(unittest.TestCase): 
    def test_true(self): 
     self.assertTrue(True) 

@contextlib.contextmanager 
def err_to(file): 
    old_err = sys.stderr 
    sys.stderr = file 
    yield 
    sys.stderr = old_err 

if __name__ == '__main__': 
    result = io.StringIO() 
    with err_to(result): 
     unittest.main(exit=False) 
    result.seek(0) 
    print(result.read()) 

这版画(sys.stdout来)

---------------------------------------------------------------------- 
Ran 1 test in 0.000s 

OK 

注:contextlib有redirect_stdout,但不redirect_stderr的。以上更简单的是contextlib代码。上面假设没有没有被unittest捕获的例外。请参阅contextlib.contextmanager文档以添加try:except:finally。我把它留给你。

+0

谢谢,这是一条有趣的路径。但我需要在测试中存储更多的信息,而不是屏幕上显示的信息。分析可能是相当单调乏味的... – 2014-10-22 20:08:08

1

我最终编写了两个新类,它们继承自unittest.TextTestResultunittest.TextTestRunner。这样一来,我可以运行主要那样:

unittest.main(testRunner=xmlrunner.XMLTestRunner(...)) 

我重载unittest.TextTestRunner__init__和来自unittest.TextTestResult

  • addSuccess()
  • addError()
  • addFailure()
  • addSubTest()

例如:

def addSuccess(self, test): 
    super().addSuccess(test) 
    [... store the test into list, dictionary, whatever... ] 

由于这些add*()函数被调用的实际测试中,我可以将它们存储在一个全局列表,并在我的XMLTestRunner.run()结束它们解析:

def run(self, test): 
    result = super().run(test) 
    self.save_xml_report(result) 
    return result 

请注意,这些功能通常在/usr/lib/python3.4/unittest/runner.py中定义。

警告注意:通过使用一个实际的对象传递unittest.main()testRunner参数如图所示,推出蟒蛇时给出的命令行参数被忽略。例如,使用-v参数增加详细级别将被忽略。这是因为在/usr/lib/python3.4/unittest/main.py中定义的TestProgram类会检测unittest.main()是否以testRunner作为类或对象运行(请参阅文件末尾附近的runTests())。如果你只给出这样一个类:

unittest.main(testRunner=xmlrunner.XMLTestRunner) 

然后命令行参数被解析。但是你传递一个实例化的对象(就像我需要的那样),runTests()就会按原样使用它。因此我不得不在自己的解析参数XMLTestRunner.__init__()

# Similar to what /usr/lib/python3.4/unittest/main.py's TestProgram._getParentArgParser() does. 
import argparse 
parser = argparse.ArgumentParser(add_help=False) 
parser.add_argument('-v', '--verbose', dest='verbosity', 
        action='store_const', const=2, default=1, # Add default=1, not present in _getParentArgParser() 
        help='Verbose output') 
parser.add_argument('-q', '--quiet', dest='verbosity', 
        action='store_const', const=0, 
        help='Quiet output') 
parser.add_argument('-f', '--failfast', dest='failfast', 
        action='store_true', 
        help='Stop on first fail or error') 
parser.add_argument('-c', '--catch', dest='catchbreak', 
        action='store_true', 
        help='Catch ctrl-C and display results so far') 
parser.add_argument('-b', '--buffer', dest='buffer', 
        action='store_true', 
        help='Buffer stdout and stderr during tests') 
+0

有可能获得更多的信息,你如何做覆盖?这正是我需要弄清楚如何去做的事情,但我不确定如何实现。 – 2016-07-18 12:34:36

+0

你的意思是'addSuccess()'和co。吗?这只是继承;子类的方法将优先于父类的方法... – 2016-07-19 13:21:21

相关问题