blob: 96d56a114e966c60890525f5921afefa4cbad5ae [file] [log] [blame]
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +00001"""Test result object"""
2
3import traceback
4
5from . import util
Michael Foord1b9e9532010-03-22 01:01:34 +00006from functools import wraps
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +00007
Michael Foordb1aa30f2010-03-22 00:06:30 +00008__unittest = True
9
Michael Foord1b9e9532010-03-22 01:01:34 +000010def failfast(method):
11 @wraps(method)
12 def inner(self, *args, **kw):
13 if getattr(self, 'failfast', False):
14 self.stop()
15 return method(self, *args, **kw)
16 return inner
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000017
18class TestResult(object):
19 """Holder for test result information.
20
21 Test results are automatically managed by the TestCase and TestSuite
22 classes, and do not need to be explicitly manipulated by writers of tests.
23
24 Each instance holds the total number of tests run, and collections of
25 failures and errors that occurred among those test runs. The collections
26 contain tuples of (testcase, exceptioninfo), where exceptioninfo is the
27 formatted traceback of the error that occurred.
28 """
Michael Foord5ffa3252010-03-07 22:04:55 +000029 _previousTestClass = None
30 _moduleSetUpFailed = False
Michael Foordd99ef9a2010-02-23 17:00:53 +000031 def __init__(self, stream=None, descriptions=None, verbosity=None):
Michael Foord1b9e9532010-03-22 01:01:34 +000032 self.failfast = False
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000033 self.failures = []
34 self.errors = []
35 self.testsRun = 0
36 self.skipped = []
37 self.expectedFailures = []
38 self.unexpectedSuccesses = []
39 self.shouldStop = False
40
Michael Foordd99ef9a2010-02-23 17:00:53 +000041 def printErrors(self):
42 "Called by TestRunner after test run"
43
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000044 def startTest(self, test):
45 "Called when the given test is about to be run"
Michael Foorddb43b5a2010-02-10 14:25:12 +000046 self.testsRun += 1
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000047
48 def startTestRun(self):
49 """Called once before any tests are executed.
50
51 See startTest for a method called before each test.
52 """
53
54 def stopTest(self, test):
Michael Foorddb43b5a2010-02-10 14:25:12 +000055 """Called when the given test has been run"""
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000056
57 def stopTestRun(self):
58 """Called once after all tests are executed.
59
60 See stopTest for a method called after each test.
61 """
62
Michael Foord1b9e9532010-03-22 01:01:34 +000063 @failfast
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000064 def addError(self, test, err):
65 """Called when an error has occurred. 'err' is a tuple of values as
66 returned by sys.exc_info().
67 """
68 self.errors.append((test, self._exc_info_to_string(err, test)))
69
Michael Foord1b9e9532010-03-22 01:01:34 +000070 @failfast
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000071 def addFailure(self, test, err):
72 """Called when an error has occurred. 'err' is a tuple of values as
73 returned by sys.exc_info()."""
74 self.failures.append((test, self._exc_info_to_string(err, test)))
75
76 def addSuccess(self, test):
77 "Called when a test has completed successfully"
78 pass
79
80 def addSkip(self, test, reason):
81 """Called when a test is skipped."""
82 self.skipped.append((test, reason))
83
Michael Foord1b9e9532010-03-22 01:01:34 +000084 @failfast
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000085 def addExpectedFailure(self, test, err):
86 """Called when an expected failure/error occured."""
87 self.expectedFailures.append(
88 (test, self._exc_info_to_string(err, test)))
89
Michael Foord1b9e9532010-03-22 01:01:34 +000090 @failfast
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000091 def addUnexpectedSuccess(self, test):
92 """Called when a test was expected to fail, but succeed."""
93 self.unexpectedSuccesses.append(test)
94
95 def wasSuccessful(self):
96 "Tells whether or not this result was a success"
97 return len(self.failures) == len(self.errors) == 0
98
99 def stop(self):
100 "Indicates that the tests should be aborted"
101 self.shouldStop = True
102
103 def _exc_info_to_string(self, err, test):
104 """Converts a sys.exc_info()-style tuple of values into a string."""
105 exctype, value, tb = err
106 # Skip test runner traceback levels
107 while tb and self._is_relevant_tb_level(tb):
108 tb = tb.tb_next
109 if exctype is test.failureException:
110 # Skip assert*() traceback levels
111 length = self._count_relevant_tb_levels(tb)
112 return ''.join(traceback.format_exception(exctype, value, tb, length))
113 return ''.join(traceback.format_exception(exctype, value, tb))
114
115 def _is_relevant_tb_level(self, tb):
Michael Foordb1aa30f2010-03-22 00:06:30 +0000116 return '__unittest' in tb.tb_frame.f_globals
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000117
118 def _count_relevant_tb_levels(self, tb):
119 length = 0
120 while tb and not self._is_relevant_tb_level(tb):
121 length += 1
122 tb = tb.tb_next
123 return length
124
125 def __repr__(self):
Michael Foordae3db0a2010-02-22 23:28:32 +0000126 return ("<%s run=%i errors=%i failures=%i>" %
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000127 (util.strclass(self.__class__), self.testsRun, len(self.errors),
Michael Foordae3db0a2010-02-22 23:28:32 +0000128 len(self.failures)))