Issue #7197: Allow unittest.TextTestRunner objects to be pickled and
[python.git] / Lib / unittest / runner.py
blob99819df85332478533e3fb9f67061a462006f9bb
1 """Running tests"""
3 import sys
4 import time
6 from . import result
9 class _WritelnDecorator(object):
10 """Used to decorate file-like objects with a handy 'writeln' method"""
11 def __init__(self,stream):
12 self.stream = stream
14 def __getattr__(self, attr):
15 if attr == 'stream':
16 raise AttributeError(attr)
17 return getattr(self.stream,attr)
19 def writeln(self, arg=None):
20 if arg:
21 self.write(arg)
22 self.write('\n') # text-mode streams translate to \r\n if needed
25 class _TextTestResult(result.TestResult):
26 """A test result class that can print formatted text results to a stream.
28 Used by TextTestRunner.
29 """
30 separator1 = '=' * 70
31 separator2 = '-' * 70
33 def __init__(self, stream, descriptions, verbosity):
34 super(_TextTestResult, self).__init__()
35 self.stream = stream
36 self.showAll = verbosity > 1
37 self.dots = verbosity == 1
38 self.descriptions = descriptions
40 def getDescription(self, test):
41 if self.descriptions:
42 return test.shortDescription() or str(test)
43 else:
44 return str(test)
46 def startTest(self, test):
47 super(_TextTestResult, self).startTest(test)
48 if self.showAll:
49 self.stream.write(self.getDescription(test))
50 self.stream.write(" ... ")
51 self.stream.flush()
53 def addSuccess(self, test):
54 super(_TextTestResult, self).addSuccess(test)
55 if self.showAll:
56 self.stream.writeln("ok")
57 elif self.dots:
58 self.stream.write('.')
59 self.stream.flush()
61 def addError(self, test, err):
62 super(_TextTestResult, self).addError(test, err)
63 if self.showAll:
64 self.stream.writeln("ERROR")
65 elif self.dots:
66 self.stream.write('E')
67 self.stream.flush()
69 def addFailure(self, test, err):
70 super(_TextTestResult, self).addFailure(test, err)
71 if self.showAll:
72 self.stream.writeln("FAIL")
73 elif self.dots:
74 self.stream.write('F')
75 self.stream.flush()
77 def addSkip(self, test, reason):
78 super(_TextTestResult, self).addSkip(test, reason)
79 if self.showAll:
80 self.stream.writeln("skipped {0!r}".format(reason))
81 elif self.dots:
82 self.stream.write("s")
83 self.stream.flush()
85 def addExpectedFailure(self, test, err):
86 super(_TextTestResult, self).addExpectedFailure(test, err)
87 if self.showAll:
88 self.stream.writeln("expected failure")
89 elif self.dots:
90 self.stream.write("x")
91 self.stream.flush()
93 def addUnexpectedSuccess(self, test):
94 super(_TextTestResult, self).addUnexpectedSuccess(test)
95 if self.showAll:
96 self.stream.writeln("unexpected success")
97 elif self.dots:
98 self.stream.write("u")
99 self.stream.flush()
101 def printErrors(self):
102 if self.dots or self.showAll:
103 self.stream.writeln()
104 self.printErrorList('ERROR', self.errors)
105 self.printErrorList('FAIL', self.failures)
107 def printErrorList(self, flavour, errors):
108 for test, err in errors:
109 self.stream.writeln(self.separator1)
110 self.stream.writeln("%s: %s" % (flavour,self.getDescription(test)))
111 self.stream.writeln(self.separator2)
112 self.stream.writeln("%s" % err)
115 class TextTestRunner(object):
116 """A test runner class that displays results in textual form.
118 It prints out the names of tests as they are run, errors as they
119 occur, and a summary of the results at the end of the test run.
121 def __init__(self, stream=sys.stderr, descriptions=1, verbosity=1):
122 self.stream = _WritelnDecorator(stream)
123 self.descriptions = descriptions
124 self.verbosity = verbosity
126 def _makeResult(self):
127 return _TextTestResult(self.stream, self.descriptions, self.verbosity)
129 def run(self, test):
130 "Run the given test case or test suite."
131 result = self._makeResult()
132 startTime = time.time()
133 startTestRun = getattr(result, 'startTestRun', None)
134 if startTestRun is not None:
135 startTestRun()
136 try:
137 test(result)
138 finally:
139 stopTestRun = getattr(result, 'stopTestRun', None)
140 if stopTestRun is not None:
141 stopTestRun()
142 stopTime = time.time()
143 timeTaken = stopTime - startTime
144 result.printErrors()
145 self.stream.writeln(result.separator2)
146 run = result.testsRun
147 self.stream.writeln("Ran %d test%s in %.3fs" %
148 (run, run != 1 and "s" or "", timeTaken))
149 self.stream.writeln()
150 results = map(len, (result.expectedFailures,
151 result.unexpectedSuccesses,
152 result.skipped))
153 expectedFails, unexpectedSuccesses, skipped = results
154 infos = []
155 if not result.wasSuccessful():
156 self.stream.write("FAILED")
157 failed, errored = map(len, (result.failures, result.errors))
158 if failed:
159 infos.append("failures=%d" % failed)
160 if errored:
161 infos.append("errors=%d" % errored)
162 else:
163 self.stream.write("OK")
164 if skipped:
165 infos.append("skipped=%d" % skipped)
166 if expectedFails:
167 infos.append("expected failures=%d" % expectedFails)
168 if unexpectedSuccesses:
169 infos.append("unexpected successes=%d" % unexpectedSuccesses)
170 if infos:
171 self.stream.writeln(" (%s)" % (", ".join(infos),))
172 else:
173 self.stream.write("\n")
174 return result