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,18 +154,20 @@ class _XMLTestResult(_TextTestResult): ...@@ -138,18 +154,20 @@ 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,
self.failures, 'FAIL', 'F') stdout=self.stdout, stderr=self.stderr),
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,
self.errors, 'ERROR', 'E') stdout=self.stdout, stderr=self.stderr),
self.errors, 'ERROR', 'E')
def printErrorList(self, flavour, errors): def printErrorList(self, flavour, errors):
"Write some information about the FAIL or ERROR to the stream." "Write some information about the FAIL or ERROR to the stream."
...@@ -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,64 +317,47 @@ class XMLTestRunner(TextTestRunner): ...@@ -297,64 +317,47 @@ 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."
# Prepare the test execution
try: result = self._make_result()
# Prepare the test execution
self._patch_standard_output() # Print a nice header
result = self._make_result() self.stream.writeln()
self.stream.writeln('Running tests...')
# Print a nice header self.stream.writeln(result.separator2)
self.stream.writeln()
self.stream.writeln('Running tests...') # Execute tests
self.stream.writeln(result.separator2) start_time = time.time()
test(result)
# Execute tests stop_time = time.time()
start_time = time.time() time_taken = stop_time - start_time
test(result)
stop_time = time.time() # Print results
time_taken = stop_time - start_time result.printErrors()
self.stream.writeln(result.separator2)
# Print results run = result.testsRun
result.printErrors() self.stream.writeln("Ran %d test%s in %.3fs" %
self.stream.writeln(result.separator2) (run, run != 1 and "s" or "", time_taken))
run = result.testsRun self.stream.writeln()
self.stream.writeln("Ran %d test%s in %.3fs" %
(run, run != 1 and "s" or "", time_taken)) # Error traces
self.stream.writeln() if not result.wasSuccessful():
self.stream.write("FAILED (")
# Error traces failed, errored = (len(result.failures), len(result.errors))
if not result.wasSuccessful(): if failed:
self.stream.write("FAILED (") self.stream.write("failures=%d" % failed)
failed, errored = (len(result.failures), len(result.errors)) if errored:
if failed: if failed:
self.stream.write("failures=%d" % failed) self.stream.write(", ")
if errored: self.stream.write("errors=%d" % errored)
if failed: self.stream.writeln(")")
self.stream.write(", ") else:
self.stream.write("errors=%d" % errored) self.stream.writeln("OK")
self.stream.writeln(")")
else: # Generate reports
self.stream.writeln("OK") self.stream.writeln()
self.stream.writeln('Generating XML reports...')
# Generate reports result.generate_reports(self)
self.stream.writeln()
self.stream.writeln('Generating XML reports...')
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