[英]Python 3 unittest: How to extract results of tests?
我正在使用 Python 的 (3.4.1) 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/ ) 但是:
我想以我需要的格式生成 XML(我不介意手动执行),但对测试的运行方式进行最小的更改。
我有哪些选择?
unittest.main()
后提取测试结果并解析它。 这里的问题是unittest.main()
似乎在完成后退出,因此它之后的任何代码都没有执行。有什么建议吗?
谢谢!
我最终编写了两个新类,继承自unittest.TextTestResult
和unittest.TextTestRunner
。 这样,我可以像这样运行 main:
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
参数,如图所示,启动 python 时给出的命令行参数将被忽略。 例如,使用-v
参数增加详细级别将被忽略。 这是因为在/usr/lib/python3.4/unittest/main.py
定义的TestProgram
类检测unittest.main()
是在testRunner
是一个类还是一个对象的情况下运行的(请参阅接近末尾的runTests()
文件)。 如果您只提供这样的课程:
unittest.main(testRunner=xmlrunner.XMLTestRunner)
然后解析命令行参数。 但是您传递了一个实例化的对象(就像我需要的那样), runTests()
将按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')
这对你有什么作用。 在 StringIO 中捕获 unittest 的输出,该输出转到 sys.stderr。 通过添加`exit = False'在unittest.main之后继续。 根据需要读取捕获的输出和处理。 概念证明:
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。 我把它留给你。
我在从 unittest lib 中捕获 FAIL 事件时遇到了同样的问题。 在 big_gie 的回答之后,出现了这段代码:
文件testFileName_1.py
import unittest
class TestClassToTestSth(unittest.TestCase):
def test_One(self):
self.AssertEqual(True, False, 'Hello world')
import unittest
from io import StringIO
import testFileName_1
def suites():
return [
# your testCase classes, for example
testFileName_1.TestClassToTestSth,
testFileName_445.TestClassToTestSomethingElse,
]
class TextTestResult(unittest.TextTestResult):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.slack = Slack('data-engineering-tests')
def addFailure(self, test, err):
super().addFailure(test, err)
# Whatever you want here
print(err, test)
print(self.failures)
class TextTestRunner(unittest.TextTestRunner):
resultclass = TextTestResult
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
loader = unittest.TestLoader()
suite = unittest.TestSuite()
stream = StringIO()
for test_case in suites():
suite.addTests(loader.loadTestsFromTestCase(test_case))
runner = TextTestRunner(stream=stream)
result = runner.run(suite)
stream.seek(0)
print(stream.read())
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.