Commit 45685d47 authored by Stefan Behnel's avatar Stefan Behnel

fix xml test result generation to restrict the captured stdout/stderr to the current test case

parent 925eb5f8
...@@ -53,12 +53,14 @@ class _TestInfo(object): ...@@ -53,12 +53,14 @@ class _TestInfo(object):
# Possible test outcomes # Possible test outcomes
(SUCCESS, FAILURE, ERROR) = range(3) (SUCCESS, FAILURE, ERROR) = range(3)
def __init__(self, test_result, test_method, outcome=SUCCESS, err=None): def __init__(self, test_result, test_method, outcome=SUCCESS, err=None, stdout=None, stderr=None):
"Create a new instance of _TestInfo." "Create a new instance of _TestInfo."
self.test_result = test_result self.test_result = test_result
self.test_method = test_method self.test_method = test_method
self.outcome = outcome self.outcome = outcome
self.err = err self.err = err
self.stdout = stdout
self.stderr = stderr
def get_elapsed_time(self): def get_elapsed_time(self):
"""Return the time that shows how long the test method took to """Return the time that shows how long the test method took to
...@@ -118,8 +120,21 @@ class _XMLTestResult(_TextTestResult): ...@@ -118,8 +120,21 @@ class _XMLTestResult(_TextTestResult):
self.stream.write(short_str) self.stream.write(short_str)
self.callback = callback self.callback = callback
def _patch_standard_output(self):
"""Replace the stdout and stderr streams with string-based streams
in order to capture the tests' output.
"""
(self.old_stdout, self.old_stderr) = (sys.stdout, sys.stderr)
(sys.stdout, sys.stderr) = (self.stdout, self.stderr) = \
(StringIO(), StringIO())
def _restore_standard_output(self):
"Restore the stdout and stderr streams."
(sys.stdout, sys.stderr) = (self.old_stdout, self.old_stderr)
def startTest(self, test): def startTest(self, test):
"Called before execute each test method." "Called before execute each test method."
self._patch_standard_output()
self.start_time = time.time() self.start_time = time.time()
TestResult.startTest(self, test) TestResult.startTest(self, test)
...@@ -129,6 +144,7 @@ class _XMLTestResult(_TextTestResult): ...@@ -129,6 +144,7 @@ class _XMLTestResult(_TextTestResult):
def stopTest(self, test): def stopTest(self, test):
"Called after execute each test method." "Called after execute each test method."
self._restore_standard_output()
_TextTestResult.stopTest(self, test) _TextTestResult.stopTest(self, test)
self.stop_time = time.time() self.stop_time = time.time()
...@@ -138,17 +154,19 @@ class _XMLTestResult(_TextTestResult): ...@@ -138,17 +154,19 @@ class _XMLTestResult(_TextTestResult):
def addSuccess(self, test): def addSuccess(self, test):
"Called when a test executes successfully." "Called when a test executes successfully."
self._prepare_callback(_TestInfo(self, test), \ self._prepare_callback(_TestInfo(self, test, stdout=self.stdout, stderr=self.stderr),
self.successes, 'OK', '.') self.successes, 'OK', '.')
def addFailure(self, test, err): def addFailure(self, test, err):
"Called when a test method fails." "Called when a test method fails."
self._prepare_callback(_TestInfo(self, test, _TestInfo.FAILURE, err), \ self._prepare_callback(_TestInfo(self, test, _TestInfo.FAILURE, err,
stdout=self.stdout, stderr=self.stderr),
self.failures, 'FAIL', 'F') self.failures, 'FAIL', 'F')
def addError(self, test, err): def addError(self, test, err):
"Called when a test method raises an error." "Called when a test method raises an error."
self._prepare_callback(_TestInfo(self, test, _TestInfo.ERROR, err), \ self._prepare_callback(_TestInfo(self, test, _TestInfo.ERROR, err,
stdout=self.stdout, stderr=self.stderr),
self.errors, 'ERROR', 'E') self.errors, 'ERROR', 'E')
def printErrorList(self, flavour, errors): def printErrorList(self, flavour, errors):
...@@ -230,19 +248,17 @@ class _XMLTestResult(_TextTestResult): ...@@ -230,19 +248,17 @@ class _XMLTestResult(_TextTestResult):
_report_testcase = staticmethod(_report_testcase) _report_testcase = staticmethod(_report_testcase)
def _report_output(test_runner, xml_testsuite, xml_document): def _report_output(test_runner, xml_testsuite, xml_document, stdout, stderr):
"Appends the system-out and system-err sections to the XML document." "Appends the system-out and system-err sections to the XML document."
systemout = xml_document.createElement('system-out') systemout = xml_document.createElement('system-out')
xml_testsuite.appendChild(systemout) xml_testsuite.appendChild(systemout)
stdout = test_runner.stdout.getvalue()
systemout_text = xml_document.createCDATASection(stdout) systemout_text = xml_document.createCDATASection(stdout)
systemout.appendChild(systemout_text) systemout.appendChild(systemout_text)
systemerr = xml_document.createElement('system-err') systemerr = xml_document.createElement('system-err')
xml_testsuite.appendChild(systemerr) xml_testsuite.appendChild(systemerr)
stderr = test_runner.stderr.getvalue()
systemerr_text = xml_document.createCDATASection(stderr) systemerr_text = xml_document.createCDATASection(stderr)
systemerr.appendChild(systemerr_text) systemerr.appendChild(systemerr_text)
...@@ -262,9 +278,13 @@ class _XMLTestResult(_TextTestResult): ...@@ -262,9 +278,13 @@ class _XMLTestResult(_TextTestResult):
# Build the XML file # Build the XML file
testsuite = _XMLTestResult._report_testsuite(suite, tests, doc) testsuite = _XMLTestResult._report_testsuite(suite, tests, doc)
stdout, stderr = [], []
for test in tests: for test in tests:
_XMLTestResult._report_testcase(suite, test, testsuite, doc) _XMLTestResult._report_testcase(suite, test, testsuite, doc)
_XMLTestResult._report_output(test_runner, testsuite, doc) stdout.append(test.stdout and test.stdout.getvalue() or '')
stderr.append(test.stderr and test.stderr.getvalue() or '')
_XMLTestResult._report_output(test_runner, testsuite, doc,
'\n'.join(stdout).strip(), '\n'.join(stderr).strip())
xml_content = doc.toprettyxml(indent='\t') xml_content = doc.toprettyxml(indent='\t')
if type(test_runner.output) is str: if type(test_runner.output) is str:
...@@ -297,24 +317,9 @@ class XMLTestRunner(TextTestRunner): ...@@ -297,24 +317,9 @@ class XMLTestRunner(TextTestRunner):
return _XMLTestResult(self.stream, self.descriptions, \ return _XMLTestResult(self.stream, self.descriptions, \
self.verbosity, self.elapsed_times) self.verbosity, self.elapsed_times)
def _patch_standard_output(self):
"""Replace the stdout and stderr streams with string-based streams
in order to capture the tests' output.
"""
(self.old_stdout, self.old_stderr) = (sys.stdout, sys.stderr)
(sys.stdout, sys.stderr) = (self.stdout, self.stderr) = \
(StringIO(), StringIO())
def _restore_standard_output(self):
"Restore the stdout and stderr streams."
(sys.stdout, sys.stderr) = (self.old_stdout, self.old_stderr)
def run(self, test): def run(self, test):
"Run the given test case or test suite." "Run the given test case or test suite."
try:
# Prepare the test execution # Prepare the test execution
self._patch_standard_output()
result = self._make_result() result = self._make_result()
# Print a nice header # Print a nice header
...@@ -354,7 +359,5 @@ class XMLTestRunner(TextTestRunner): ...@@ -354,7 +359,5 @@ class XMLTestRunner(TextTestRunner):
self.stream.writeln() self.stream.writeln()
self.stream.writeln('Generating XML reports...') self.stream.writeln('Generating XML reports...')
result.generate_reports(self) result.generate_reports(self)
finally:
self._restore_standard_output()
return result return result
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment