blob: ec80e8eea5871c4a6c9aa856f902ecfbba2a20db [file] [log] [blame]
Benjamin Petersonbed7d042009-07-19 21:01:52 +00001"""Test result object"""
2
3import traceback
4
5from . import util
Benjamin Peterson8769fd82010-03-22 01:13:48 +00006from functools import wraps
Benjamin Petersonbed7d042009-07-19 21:01:52 +00007
Benjamin Petersondccc1fc2010-03-22 00:15:53 +00008__unittest = True
9
Benjamin Peterson8769fd82010-03-22 01:13:48 +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 Petersonbed7d042009-07-19 21:01:52 +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 """
Benjamin Peterson847a4112010-03-14 15:04:17 +000029 _previousTestClass = None
30 _moduleSetUpFailed = False
31 def __init__(self, stream=None, descriptions=None, verbosity=None):
Benjamin Peterson8769fd82010-03-22 01:13:48 +000032 self.failfast = False
Benjamin Petersonbed7d042009-07-19 21:01:52 +000033 self.failures = []
34 self.errors = []
35 self.testsRun = 0
36 self.skipped = []
37 self.expectedFailures = []
38 self.unexpectedSuccesses = []
39 self.shouldStop = False
40
Benjamin Peterson847a4112010-03-14 15:04:17 +000041 def printErrors(self):
42 "Called by TestRunner after test run"
43
Benjamin Petersonbed7d042009-07-19 21:01:52 +000044 def startTest(self, test):
45 "Called when the given test is about to be run"
Michael Foord34c94622010-02-10 15:51:42 +000046 self.testsRun += 1
Benjamin Petersonbed7d042009-07-19 21:01:52 +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 Foord34c94622010-02-10 15:51:42 +000055 """Called when the given test has been run"""
Benjamin Petersonbed7d042009-07-19 21:01:52 +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
Benjamin Peterson8769fd82010-03-22 01:13:48 +000063 @failfast
Benjamin Petersonbed7d042009-07-19 21:01:52 +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
Benjamin Peterson8769fd82010-03-22 01:13:48 +000070 @failfast
Benjamin Petersonbed7d042009-07-19 21:01:52 +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
84 def addExpectedFailure(self, test, err):
85 """Called when an expected failure/error occured."""
86 self.expectedFailures.append(
87 (test, self._exc_info_to_string(err, test)))
88
Benjamin Peterson8769fd82010-03-22 01:13:48 +000089 @failfast
Benjamin Petersonbed7d042009-07-19 21:01:52 +000090 def addUnexpectedSuccess(self, test):
91 """Called when a test was expected to fail, but succeed."""
92 self.unexpectedSuccesses.append(test)
93
94 def wasSuccessful(self):
95 "Tells whether or not this result was a success"
96 return len(self.failures) == len(self.errors) == 0
97
98 def stop(self):
99 "Indicates that the tests should be aborted"
100 self.shouldStop = True
101
102 def _exc_info_to_string(self, err, test):
103 """Converts a sys.exc_info()-style tuple of values into a string."""
104 exctype, value, tb = err
105 # Skip test runner traceback levels
106 while tb and self._is_relevant_tb_level(tb):
107 tb = tb.tb_next
108 if exctype is test.failureException:
109 # Skip assert*() traceback levels
110 length = self._count_relevant_tb_levels(tb)
111 return ''.join(traceback.format_exception(exctype, value, tb, length))
112 return ''.join(traceback.format_exception(exctype, value, tb))
113
114 def _is_relevant_tb_level(self, tb):
Benjamin Petersondccc1fc2010-03-22 00:15:53 +0000115 return '__unittest' in tb.tb_frame.f_globals
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000116
117 def _count_relevant_tb_levels(self, tb):
118 length = 0
119 while tb and not self._is_relevant_tb_level(tb):
120 length += 1
121 tb = tb.tb_next
122 return length
123
124 def __repr__(self):
Benjamin Peterson847a4112010-03-14 15:04:17 +0000125 return ("<%s run=%i errors=%i failures=%i>" %
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000126 (util.strclass(self.__class__), self.testsRun, len(self.errors),
Benjamin Peterson847a4112010-03-14 15:04:17 +0000127 len(self.failures)))