1 """Test result object"""
9 from six import StringIO as SixStringIO
11 from unittest2 import util
12 from unittest2.compatibility import wraps
18 def inner(self, *args, **kw):
19 if getattr(self, 'failfast', False):
21 return method(self, *args, **kw)
25 STDOUT_LINE = '\nStdout:\n%s'
26 STDERR_LINE = '\nStderr:\n%s'
28 class TestResult(unittest.TestResult):
29 """Holder for test result information.
31 Test results are automatically managed by the TestCase and TestSuite
32 classes, and do not need to be explicitly manipulated by writers of tests.
34 Each instance holds the total number of tests run, and collections of
35 failures and errors that occurred among those test runs. The collections
36 contain tuples of (testcase, exceptioninfo), where exceptioninfo is the
37 formatted traceback of the error that occurred.
39 _previousTestClass = None
40 _moduleSetUpFailed = False
47 self.cleanup_errors = []
50 self.expectedFailures = []
51 self.unexpectedSuccesses = []
52 self.shouldStop = False
54 self._stdout_buffer = None
55 self._stderr_buffer = None
56 self._original_stdout = sys.stdout
57 self._original_stderr = sys.stderr
58 self._mirrorOutput = False
60 def startTest(self, test):
61 "Called when the given test is about to be run"
63 self._mirrorOutput = False
65 if self._stderr_buffer is None:
66 self._stderr_buffer = SixStringIO()
67 self._stdout_buffer = SixStringIO()
68 sys.stdout = self._stdout_buffer
69 sys.stderr = self._stderr_buffer
71 def startTestRun(self):
72 """Called once before any tests are executed.
74 See startTest for a method called before each test.
77 def stopTest(self, test):
78 """Called when the given test has been run"""
80 if self._mirrorOutput:
81 output = sys.stdout.getvalue()
82 error = sys.stderr.getvalue()
84 if not output.endswith('\n'):
86 self._original_stdout.write(STDOUT_LINE % output)
88 if not error.endswith('\n'):
90 self._original_stderr.write(STDERR_LINE % error)
92 sys.stdout = self._original_stdout
93 sys.stderr = self._original_stderr
94 self._stdout_buffer.seek(0)
95 self._stdout_buffer.truncate()
96 self._stderr_buffer.seek(0)
97 self._stderr_buffer.truncate()
98 self._mirrorOutput = False
101 def stopTestRun(self):
102 """Called once after all tests are executed.
104 See stopTest for a method called after each test.
108 def addError(self, test, err):
109 """Called when an error has occurred. 'err' is a tuple of values as
110 returned by sys.exc_info().
112 self.errors.append((test, self._exc_info_to_string(err, test)))
113 self._mirrorOutput = True
115 def addCleanupError(self, test, err):
116 """Called when an error has occurred during cleanup. 'err' is a tuple of
117 values as returned by sys.exc_info().
119 self.cleanup_errors.append((test, self._exc_info_to_string(err, test)))
120 self._mirrorOutput = True
123 def addFailure(self, test, err):
124 """Called when an error has occurred. 'err' is a tuple of values as
125 returned by sys.exc_info()."""
126 self.failures.append((test, self._exc_info_to_string(err, test)))
127 self._mirrorOutput = True
129 def addSuccess(self, test):
130 "Called when a test has completed successfully"
131 self.passes.append(test)
134 def addSkip(self, test, reason):
135 """Called when a test is skipped."""
136 self.skipped.append((test, reason))
138 def addExpectedFailure(self, test, err, bugnumber):
139 """Called when an expected failure/error occured."""
140 self.expectedFailures.append(
141 (test, self._exc_info_to_string(err, test)))
144 def addUnexpectedSuccess(self, test, bugnumber):
145 """Called when a test was expected to fail, but succeed."""
146 self.unexpectedSuccesses.append(test)
148 def wasSuccessful(self):
149 "Tells whether or not this result was a success"
150 return (len(self.failures) + len(self.errors) == 0)
153 "Indicates that the tests should be aborted"
154 self.shouldStop = True
156 def _exc_info_to_string(self, err, test):
157 """Converts a sys.exc_info()-style tuple of values into a string."""
158 exctype, value, tb = err
159 # Skip test runner traceback levels
160 while tb and self._is_relevant_tb_level(tb):
162 if exctype is test.failureException:
163 # Skip assert*() traceback levels
164 length = self._count_relevant_tb_levels(tb)
165 msgLines = traceback.format_exception(exctype, value, tb, length)
167 msgLines = traceback.format_exception(exctype, value, tb)
170 output = sys.stdout.getvalue()
171 error = sys.stderr.getvalue()
173 if not output.endswith('\n'):
175 msgLines.append(STDOUT_LINE % output)
177 if not error.endswith('\n'):
179 msgLines.append(STDERR_LINE % error)
180 return ''.join(msgLines)
182 def _is_relevant_tb_level(self, tb):
183 return '__unittest' in tb.tb_frame.f_globals
185 def _count_relevant_tb_levels(self, tb):
187 while tb and not self._is_relevant_tb_level(tb):
193 return "<%s run=%i errors=%i failures=%i>" % \
194 (util.strclass(self.__class__), self.testsRun, len(self.errors),