blob: 96d56a114e966c60890525f5921afefa4cbad5ae [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
Benjamin Peterson8769fd82010-03-22 01:13:48 +000084 @failfast
Benjamin Petersonbed7d042009-07-19 21:01:52 +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
Benjamin Peterson8769fd82010-03-22 01:13:48 +000090 @failfast
Benjamin Petersonbed7d042009-07-19 21:01:52 +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):
Benjamin Petersondccc1fc2010-03-22 00:15:53 +0000116 return '__unittest' in tb.tb_frame.f_globals
Benjamin Petersonbed7d042009-07-19 21:01:52 +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):
Benjamin Peterson847a4112010-03-14 15:04:17 +0000126 return ("<%s run=%i errors=%i failures=%i>" %
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000127 (util.strclass(self.__class__), self.testsRun, len(self.errors),
Benjamin Peterson847a4112010-03-14 15:04:17 +0000128 len(self.failures)))