1 """Test result object"""
9 from six import StringIO as SixStringIO
11 from unittest2 import util
12 from unittest2.compatibility import wraps
19 def inner(self, *args, **kw):
20 if getattr(self, 'failfast', False):
22 return method(self, *args, **kw)
26 STDOUT_LINE = '\nStdout:\n%s'
27 STDERR_LINE = '\nStderr:\n%s'
30 class TestResult(unittest.TestResult):
31 """Holder for test result information.
33 Test results are automatically managed by the TestCase and TestSuite
34 classes, and do not need to be explicitly manipulated by writers of tests.
36 Each instance holds the total number of tests run, and collections of
37 failures and errors that occurred among those test runs. The collections
38 contain tuples of (testcase, exceptioninfo), where exceptioninfo is the
39 formatted traceback of the error that occurred.
41 _previousTestClass = None
42 _moduleSetUpFailed = False
49 self.cleanup_errors = []
52 self.expectedFailures = []
53 self.unexpectedSuccesses = []
54 self.shouldStop = False
56 self._stdout_buffer = None
57 self._stderr_buffer = None
58 self._original_stdout = sys.stdout
59 self._original_stderr = sys.stderr
60 self._mirrorOutput = False
62 def startTest(self, test):
63 "Called when the given test is about to be run"
65 self._mirrorOutput = False
67 if self._stderr_buffer is None:
68 self._stderr_buffer = SixStringIO()
69 self._stdout_buffer = SixStringIO()
70 sys.stdout = self._stdout_buffer
71 sys.stderr = self._stderr_buffer
73 def startTestRun(self):
74 """Called once before any tests are executed.
76 See startTest for a method called before each test.
79 def stopTest(self, test):
80 """Called when the given test has been run"""
82 if self._mirrorOutput:
83 output = sys.stdout.getvalue()
84 error = sys.stderr.getvalue()
86 if not output.endswith('\n'):
88 self._original_stdout.write(STDOUT_LINE % output)
90 if not error.endswith('\n'):
92 self._original_stderr.write(STDERR_LINE % error)
94 sys.stdout = self._original_stdout
95 sys.stderr = self._original_stderr
96 self._stdout_buffer.seek(0)
97 self._stdout_buffer.truncate()
98 self._stderr_buffer.seek(0)
99 self._stderr_buffer.truncate()
100 self._mirrorOutput = False
102 def stopTestRun(self):
103 """Called once after all tests are executed.
105 See stopTest for a method called after each test.
109 def addError(self, test, err):
110 """Called when an error has occurred. 'err' is a tuple of values as
111 returned by sys.exc_info().
113 self.errors.append((test, self._exc_info_to_string(err, test)))
114 self._mirrorOutput = True
116 def addCleanupError(self, test, err):
117 """Called when an error has occurred during cleanup. 'err' is a tuple of
118 values as returned by sys.exc_info().
120 self.cleanup_errors.append((test, self._exc_info_to_string(err, test)))
121 self._mirrorOutput = True
124 def addFailure(self, test, err):
125 """Called when an error has occurred. 'err' is a tuple of values as
126 returned by sys.exc_info()."""
127 self.failures.append((test, self._exc_info_to_string(err, test)))
128 self._mirrorOutput = True
130 def addSuccess(self, test):
131 "Called when a test has completed successfully"
132 self.passes.append(test)
135 def addSkip(self, test, reason):
136 """Called when a test is skipped."""
137 self.skipped.append((test, reason))
139 def addExpectedFailure(self, test, err, bugnumber):
140 """Called when an expected failure/error occured."""
141 self.expectedFailures.append(
142 (test, self._exc_info_to_string(err, test)))
145 def addUnexpectedSuccess(self, test, bugnumber):
146 """Called when a test was expected to fail, but succeed."""
147 self.unexpectedSuccesses.append(test)
149 def wasSuccessful(self):
150 "Tells whether or not this result was a success"
151 return (len(self.failures) + len(self.errors) == 0)
154 "Indicates that the tests should be aborted"
155 self.shouldStop = True
157 def _exc_info_to_string(self, err, test):
158 """Converts a sys.exc_info()-style tuple of values into a string."""
159 exctype, value, tb = err
160 # Skip test runner traceback levels
161 while tb and self._is_relevant_tb_level(tb):
163 if exctype is test.failureException:
164 # Skip assert*() traceback levels
165 length = self._count_relevant_tb_levels(tb)
166 msgLines = traceback.format_exception(exctype, value, tb, length)
168 msgLines = traceback.format_exception(exctype, value, tb)
171 output = sys.stdout.getvalue()
172 error = sys.stderr.getvalue()
174 if not output.endswith('\n'):
176 msgLines.append(STDOUT_LINE % output)
178 if not error.endswith('\n'):
180 msgLines.append(STDERR_LINE % error)
181 return ''.join(msgLines)
183 def _is_relevant_tb_level(self, tb):
184 return '__unittest' in tb.tb_frame.f_globals
186 def _count_relevant_tb_levels(self, tb):
188 while tb and not self._is_relevant_tb_level(tb):
194 return "<%s run=%i errors=%i failures=%i>" % \
195 (util.strclass(self.__class__), self.testsRun, len(self.errors),