Skip to content

Commit cbf1c55

Browse files
committed
Merge pull request #96 from tkanemoto/master
Fix 'getvalue' AttributeError when test fails during __call__
2 parents f0910b7 + be41af5 commit cbf1c55

File tree

2 files changed

+44
-7
lines changed

2 files changed

+44
-7
lines changed

tests/testsuite.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,17 @@ def test_subTest_fail(self):
8181
with self.subTest(i=i):
8282
self.fail('this is a subtest.')
8383

84+
class DummyErrorInCallTest(unittest.TestCase):
85+
def __call__(self, result):
86+
try:
87+
raise Exception('Massive fail')
88+
except Exception:
89+
result.addError(self, sys.exc_info())
90+
return
91+
super(DummyErrorInCallTest, self).__call__(result)
92+
def test_pass(self):
93+
pass
94+
8495
def setUp(self):
8596
self.stream = StringIO()
8697
self.outdir = mkdtemp()
@@ -375,3 +386,9 @@ def test_xmlrunner_patched_stdout(self):
375386
finally:
376387
sys.stdout, sys.stderr = old_stdout, old_stderr
377388

389+
def test_xmlrunner_error_in_call(self):
390+
suite = unittest.TestSuite()
391+
suite.addTest(self.DummyErrorInCallTest('test_pass'))
392+
self._test_xmlrunner(suite)
393+
testsuite_output = self.stream.getvalue()
394+
self.assertIn('Exception: Massive fail', testsuite_output)

xmlrunner/result.py

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -190,8 +190,13 @@ def startTest(self, test):
190190
self.stream.write(" ... ")
191191

192192
def _save_output_data(self):
193-
self._stdout_data = sys.stdout.getvalue()
194-
self._stderr_data = sys.stderr.getvalue()
193+
# Only try to get sys.stdout and sys.sterr as they not be
194+
# StringIO yet, e.g. when test fails during __call__
195+
try:
196+
self._stdout_data = sys.stdout.getvalue()
197+
self._stderr_data = sys.stderr.getvalue()
198+
except AttributeError:
199+
pass
195200

196201
def stopTest(self, test):
197202
"""
@@ -343,7 +348,8 @@ def _report_testsuite(suite_name, suite, tests, xml_document, parentElement,
343348
stdout = StringIO()
344349
for test in tests:
345350
# Merge the stdout from the tests in a class
346-
stdout.write(test.stdout)
351+
if test.stdout is not None:
352+
stdout.write(test.stdout)
347353
_XMLTestResult._createCDATAsections(
348354
xml_document, systemout, stdout.getvalue())
349355

@@ -353,7 +359,8 @@ def _report_testsuite(suite_name, suite, tests, xml_document, parentElement,
353359
stderr = StringIO()
354360
for test in tests:
355361
# Merge the stderr from the tests in a class
356-
stderr.write(test.stderr)
362+
if test.stderr is not None:
363+
stderr.write(test.stderr)
357364
_XMLTestResult._createCDATAsections(
358365
xml_document, systemerr, stderr.getvalue())
359366

@@ -471,7 +478,12 @@ def _exc_info_to_string(self, err, test):
471478
"""Converts a sys.exc_info()-style tuple of values into a string."""
472479
if six.PY3:
473480
# It works fine in python 3
474-
return super(_XMLTestResult, self)._exc_info_to_string(err, test)
481+
try:
482+
return super(_XMLTestResult, self)._exc_info_to_string(
483+
err, test)
484+
except AttributeError:
485+
# We keep going using the legacy python <= 2 way
486+
pass
475487

476488
# This comes directly from python2 unittest
477489
exctype, value, tb = err
@@ -487,8 +499,16 @@ def _exc_info_to_string(self, err, test):
487499
msgLines = traceback.format_exception(exctype, value, tb)
488500

489501
if self.buffer:
490-
output = sys.stdout.getvalue()
491-
error = sys.stderr.getvalue()
502+
# Only try to get sys.stdout and sys.sterr as they not be
503+
# StringIO yet, e.g. when test fails during __call__
504+
try:
505+
output = sys.stdout.getvalue()
506+
except AttributeError:
507+
output = None
508+
try:
509+
error = sys.stderr.getvalue()
510+
except AttributeError:
511+
error = None
492512
if output:
493513
if not output.endswith('\n'):
494514
output += '\n'

0 commit comments

Comments
 (0)