blob: caf159002d8bb6778b53315a96dabc2e177ac23c [file] [log] [blame]
Benjamin Petersonbed7d042009-07-19 21:01:52 +00001"""Running tests"""
2
3import sys
4import time
Ezio Melotti60901872010-12-01 00:56:10 +00005import warnings
Benjamin Petersonbed7d042009-07-19 21:01:52 +00006
7from . import result
Michael Foord65b69a12010-03-27 13:25:41 +00008from .signals import registerResult
Benjamin Petersonbed7d042009-07-19 21:01:52 +00009
Benjamin Petersondccc1fc2010-03-22 00:15:53 +000010__unittest = True
11
Benjamin Petersonbed7d042009-07-19 21:01:52 +000012
13class _WritelnDecorator(object):
14 """Used to decorate file-like objects with a handy 'writeln' method"""
15 def __init__(self,stream):
16 self.stream = stream
17
18 def __getattr__(self, attr):
Antoine Pitrouc63ecee2009-11-10 21:34:48 +000019 if attr in ('stream', '__getstate__'):
20 raise AttributeError(attr)
Benjamin Petersonbed7d042009-07-19 21:01:52 +000021 return getattr(self.stream,attr)
22
23 def writeln(self, arg=None):
24 if arg:
25 self.write(arg)
26 self.write('\n') # text-mode streams translate to \r\n if needed
27
28
Michael Foord34c94622010-02-10 15:51:42 +000029class TextTestResult(result.TestResult):
Benjamin Petersonbed7d042009-07-19 21:01:52 +000030 """A test result class that can print formatted text results to a stream.
31
32 Used by TextTestRunner.
33 """
34 separator1 = '=' * 70
35 separator2 = '-' * 70
36
37 def __init__(self, stream, descriptions, verbosity):
Michael Foord7a1901f2012-09-28 14:14:03 +010038 super(TextTestResult, self).__init__(stream, descriptions, verbosity)
Benjamin Petersonbed7d042009-07-19 21:01:52 +000039 self.stream = stream
40 self.showAll = verbosity > 1
41 self.dots = verbosity == 1
42 self.descriptions = descriptions
43
44 def getDescription(self, test):
Michael Foord34c94622010-02-10 15:51:42 +000045 doc_first_line = test.shortDescription()
46 if self.descriptions and doc_first_line:
47 return '\n'.join((str(test), doc_first_line))
Benjamin Petersonbed7d042009-07-19 21:01:52 +000048 else:
49 return str(test)
50
51 def startTest(self, test):
Michael Foord34c94622010-02-10 15:51:42 +000052 super(TextTestResult, self).startTest(test)
Benjamin Petersonbed7d042009-07-19 21:01:52 +000053 if self.showAll:
54 self.stream.write(self.getDescription(test))
55 self.stream.write(" ... ")
56 self.stream.flush()
57
58 def addSuccess(self, test):
Michael Foord34c94622010-02-10 15:51:42 +000059 super(TextTestResult, self).addSuccess(test)
Benjamin Petersonbed7d042009-07-19 21:01:52 +000060 if self.showAll:
61 self.stream.writeln("ok")
Serhiy Storchaka83fa1292021-12-11 01:36:15 +020062 self.stream.flush()
Benjamin Petersonbed7d042009-07-19 21:01:52 +000063 elif self.dots:
64 self.stream.write('.')
65 self.stream.flush()
66
67 def addError(self, test, err):
Michael Foord34c94622010-02-10 15:51:42 +000068 super(TextTestResult, self).addError(test, err)
Benjamin Petersonbed7d042009-07-19 21:01:52 +000069 if self.showAll:
70 self.stream.writeln("ERROR")
Serhiy Storchaka83fa1292021-12-11 01:36:15 +020071 self.stream.flush()
Benjamin Petersonbed7d042009-07-19 21:01:52 +000072 elif self.dots:
73 self.stream.write('E')
74 self.stream.flush()
75
76 def addFailure(self, test, err):
Michael Foord34c94622010-02-10 15:51:42 +000077 super(TextTestResult, self).addFailure(test, err)
Benjamin Petersonbed7d042009-07-19 21:01:52 +000078 if self.showAll:
79 self.stream.writeln("FAIL")
Serhiy Storchaka83fa1292021-12-11 01:36:15 +020080 self.stream.flush()
Benjamin Petersonbed7d042009-07-19 21:01:52 +000081 elif self.dots:
82 self.stream.write('F')
83 self.stream.flush()
84
85 def addSkip(self, test, reason):
Michael Foord34c94622010-02-10 15:51:42 +000086 super(TextTestResult, self).addSkip(test, reason)
Benjamin Petersonbed7d042009-07-19 21:01:52 +000087 if self.showAll:
88 self.stream.writeln("skipped {0!r}".format(reason))
Serhiy Storchaka83fa1292021-12-11 01:36:15 +020089 self.stream.flush()
Benjamin Petersonbed7d042009-07-19 21:01:52 +000090 elif self.dots:
91 self.stream.write("s")
92 self.stream.flush()
93
94 def addExpectedFailure(self, test, err):
Michael Foord34c94622010-02-10 15:51:42 +000095 super(TextTestResult, self).addExpectedFailure(test, err)
Benjamin Petersonbed7d042009-07-19 21:01:52 +000096 if self.showAll:
97 self.stream.writeln("expected failure")
Serhiy Storchaka83fa1292021-12-11 01:36:15 +020098 self.stream.flush()
Benjamin Petersonbed7d042009-07-19 21:01:52 +000099 elif self.dots:
100 self.stream.write("x")
101 self.stream.flush()
102
103 def addUnexpectedSuccess(self, test):
Michael Foord34c94622010-02-10 15:51:42 +0000104 super(TextTestResult, self).addUnexpectedSuccess(test)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000105 if self.showAll:
106 self.stream.writeln("unexpected success")
Serhiy Storchaka83fa1292021-12-11 01:36:15 +0200107 self.stream.flush()
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000108 elif self.dots:
109 self.stream.write("u")
110 self.stream.flush()
111
112 def printErrors(self):
113 if self.dots or self.showAll:
114 self.stream.writeln()
Serhiy Storchaka83fa1292021-12-11 01:36:15 +0200115 self.stream.flush()
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000116 self.printErrorList('ERROR', self.errors)
117 self.printErrorList('FAIL', self.failures)
118
119 def printErrorList(self, flavour, errors):
120 for test, err in errors:
121 self.stream.writeln(self.separator1)
122 self.stream.writeln("%s: %s" % (flavour,self.getDescription(test)))
123 self.stream.writeln(self.separator2)
124 self.stream.writeln("%s" % err)
Serhiy Storchaka83fa1292021-12-11 01:36:15 +0200125 self.stream.flush()
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000126
127
128class TextTestRunner(object):
129 """A test runner class that displays results in textual form.
130
131 It prints out the names of tests as they are run, errors as they
132 occur, and a summary of the results at the end of the test run.
133 """
Michael Foord34c94622010-02-10 15:51:42 +0000134 resultclass = TextTestResult
135
Michael Foord6f17e2d2010-12-30 19:36:29 +0000136 def __init__(self, stream=None, descriptions=True, verbosity=1,
Robert Collinsf0c819a2015-03-06 13:46:35 +1300137 failfast=False, buffer=False, resultclass=None, warnings=None,
138 *, tb_locals=False):
139 """Construct a TextTestRunner.
140
141 Subclasses should accept **kwargs to ensure compatibility as the
142 interface changes.
143 """
Michael Foord6f17e2d2010-12-30 19:36:29 +0000144 if stream is None:
145 stream = sys.stderr
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000146 self.stream = _WritelnDecorator(stream)
147 self.descriptions = descriptions
148 self.verbosity = verbosity
Benjamin Peterson8769fd82010-03-22 01:13:48 +0000149 self.failfast = failfast
Benjamin Petersonb48af542010-04-11 20:43:16 +0000150 self.buffer = buffer
Robert Collinsf0c819a2015-03-06 13:46:35 +1300151 self.tb_locals = tb_locals
Ezio Melotti60901872010-12-01 00:56:10 +0000152 self.warnings = warnings
Michael Foord34c94622010-02-10 15:51:42 +0000153 if resultclass is not None:
154 self.resultclass = resultclass
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000155
156 def _makeResult(self):
Michael Foord34c94622010-02-10 15:51:42 +0000157 return self.resultclass(self.stream, self.descriptions, self.verbosity)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000158
159 def run(self, test):
160 "Run the given test case or test suite."
161 result = self._makeResult()
Michael Foord65b69a12010-03-27 13:25:41 +0000162 registerResult(result)
Benjamin Peterson8769fd82010-03-22 01:13:48 +0000163 result.failfast = self.failfast
Benjamin Petersonb48af542010-04-11 20:43:16 +0000164 result.buffer = self.buffer
Robert Collinsf0c819a2015-03-06 13:46:35 +1300165 result.tb_locals = self.tb_locals
Ezio Melotti60901872010-12-01 00:56:10 +0000166 with warnings.catch_warnings():
167 if self.warnings:
168 # if self.warnings is set, use it to filter all the warnings
169 warnings.simplefilter(self.warnings)
170 # if the filter is 'default' or 'always', special-case the
171 # warnings from the deprecated unittest methods to show them
172 # no more than once per module, because they can be fairly
173 # noisy. The -Wd and -Wa flags can be used to bypass this
174 # only when self.warnings is None.
175 if self.warnings in ['default', 'always']:
176 warnings.filterwarnings('module',
177 category=DeprecationWarning,
R David Murray44b548d2016-09-08 13:59:53 -0400178 message=r'Please use assert\w+ instead.')
Victor Stinner8db5b542018-12-17 11:30:34 +0100179 startTime = time.perf_counter()
Ezio Melotti60901872010-12-01 00:56:10 +0000180 startTestRun = getattr(result, 'startTestRun', None)
181 if startTestRun is not None:
182 startTestRun()
183 try:
184 test(result)
185 finally:
186 stopTestRun = getattr(result, 'stopTestRun', None)
187 if stopTestRun is not None:
188 stopTestRun()
Victor Stinner8db5b542018-12-17 11:30:34 +0100189 stopTime = time.perf_counter()
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000190 timeTaken = stopTime - startTime
191 result.printErrors()
Benjamin Peterson847a4112010-03-14 15:04:17 +0000192 if hasattr(result, 'separator2'):
193 self.stream.writeln(result.separator2)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000194 run = result.testsRun
195 self.stream.writeln("Ran %d test%s in %.3fs" %
196 (run, run != 1 and "s" or "", timeTaken))
197 self.stream.writeln()
Benjamin Peterson847a4112010-03-14 15:04:17 +0000198
199 expectedFails = unexpectedSuccesses = skipped = 0
200 try:
201 results = map(len, (result.expectedFailures,
202 result.unexpectedSuccesses,
203 result.skipped))
Benjamin Peterson847a4112010-03-14 15:04:17 +0000204 except AttributeError:
205 pass
Benjamin Peterson29bd8402010-11-18 14:14:43 +0000206 else:
207 expectedFails, unexpectedSuccesses, skipped = results
Benjamin Peterson847a4112010-03-14 15:04:17 +0000208
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000209 infos = []
210 if not result.wasSuccessful():
211 self.stream.write("FAILED")
212 failed, errored = len(result.failures), len(result.errors)
213 if failed:
214 infos.append("failures=%d" % failed)
215 if errored:
216 infos.append("errors=%d" % errored)
217 else:
218 self.stream.write("OK")
219 if skipped:
220 infos.append("skipped=%d" % skipped)
221 if expectedFails:
222 infos.append("expected failures=%d" % expectedFails)
223 if unexpectedSuccesses:
224 infos.append("unexpected successes=%d" % unexpectedSuccesses)
225 if infos:
226 self.stream.writeln(" (%s)" % (", ".join(infos),))
227 else:
228 self.stream.write("\n")
Serhiy Storchaka83fa1292021-12-11 01:36:15 +0200229 self.stream.flush()
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000230 return result