blob: 7632fe9823ce51242cda0f17f885b149183ffc81 [file] [log] [blame]
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +00001"""Running tests"""
2
3import sys
4import time
5
6from . import result
Michael Foordfa2f1cd2010-03-26 03:18:31 +00007from .signals import registerResult
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +00008
Michael Foordb1aa30f2010-03-22 00:06:30 +00009__unittest = True
10
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000011
12class _WritelnDecorator(object):
13 """Used to decorate file-like objects with a handy 'writeln' method"""
14 def __init__(self,stream):
15 self.stream = stream
16
17 def __getattr__(self, attr):
Antoine Pitrou47dded62009-11-10 21:39:25 +000018 if attr in ('stream', '__getstate__'):
Antoine Pitrou0734c632009-11-10 20:49:30 +000019 raise AttributeError(attr)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000020 return getattr(self.stream,attr)
21
22 def writeln(self, arg=None):
23 if arg:
24 self.write(arg)
25 self.write('\n') # text-mode streams translate to \r\n if needed
26
27
Michael Foorddb43b5a2010-02-10 14:25:12 +000028class TextTestResult(result.TestResult):
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000029 """A test result class that can print formatted text results to a stream.
30
31 Used by TextTestRunner.
32 """
33 separator1 = '=' * 70
34 separator2 = '-' * 70
35
36 def __init__(self, stream, descriptions, verbosity):
Michael Foordbf2ad342012-09-28 12:54:56 +010037 super(TextTestResult, self).__init__(stream, descriptions, verbosity)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000038 self.stream = stream
39 self.showAll = verbosity > 1
40 self.dots = verbosity == 1
41 self.descriptions = descriptions
42
43 def getDescription(self, test):
Michael Foorddb43b5a2010-02-10 14:25:12 +000044 doc_first_line = test.shortDescription()
45 if self.descriptions and doc_first_line:
46 return '\n'.join((str(test), doc_first_line))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000047 else:
48 return str(test)
49
50 def startTest(self, test):
Michael Foorddb43b5a2010-02-10 14:25:12 +000051 super(TextTestResult, self).startTest(test)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000052 if self.showAll:
53 self.stream.write(self.getDescription(test))
54 self.stream.write(" ... ")
55 self.stream.flush()
56
57 def addSuccess(self, test):
Michael Foorddb43b5a2010-02-10 14:25:12 +000058 super(TextTestResult, self).addSuccess(test)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000059 if self.showAll:
60 self.stream.writeln("ok")
61 elif self.dots:
62 self.stream.write('.')
63 self.stream.flush()
64
65 def addError(self, test, err):
Michael Foorddb43b5a2010-02-10 14:25:12 +000066 super(TextTestResult, self).addError(test, err)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000067 if self.showAll:
68 self.stream.writeln("ERROR")
69 elif self.dots:
70 self.stream.write('E')
71 self.stream.flush()
72
73 def addFailure(self, test, err):
Michael Foorddb43b5a2010-02-10 14:25:12 +000074 super(TextTestResult, self).addFailure(test, err)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000075 if self.showAll:
76 self.stream.writeln("FAIL")
77 elif self.dots:
78 self.stream.write('F')
79 self.stream.flush()
80
81 def addSkip(self, test, reason):
Michael Foorddb43b5a2010-02-10 14:25:12 +000082 super(TextTestResult, self).addSkip(test, reason)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000083 if self.showAll:
84 self.stream.writeln("skipped {0!r}".format(reason))
85 elif self.dots:
86 self.stream.write("s")
87 self.stream.flush()
88
89 def addExpectedFailure(self, test, err):
Michael Foorddb43b5a2010-02-10 14:25:12 +000090 super(TextTestResult, self).addExpectedFailure(test, err)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000091 if self.showAll:
92 self.stream.writeln("expected failure")
93 elif self.dots:
94 self.stream.write("x")
95 self.stream.flush()
96
97 def addUnexpectedSuccess(self, test):
Michael Foorddb43b5a2010-02-10 14:25:12 +000098 super(TextTestResult, self).addUnexpectedSuccess(test)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000099 if self.showAll:
100 self.stream.writeln("unexpected success")
101 elif self.dots:
102 self.stream.write("u")
103 self.stream.flush()
104
105 def printErrors(self):
106 if self.dots or self.showAll:
107 self.stream.writeln()
108 self.printErrorList('ERROR', self.errors)
109 self.printErrorList('FAIL', self.failures)
110
111 def printErrorList(self, flavour, errors):
112 for test, err in errors:
113 self.stream.writeln(self.separator1)
114 self.stream.writeln("%s: %s" % (flavour,self.getDescription(test)))
115 self.stream.writeln(self.separator2)
116 self.stream.writeln("%s" % err)
117
118
119class TextTestRunner(object):
120 """A test runner class that displays results in textual form.
121
122 It prints out the names of tests as they are run, errors as they
123 occur, and a summary of the results at the end of the test run.
124 """
Michael Foorddb43b5a2010-02-10 14:25:12 +0000125 resultclass = TextTestResult
126
127 def __init__(self, stream=sys.stderr, descriptions=True, verbosity=1,
Michael Foord5637f042010-04-02 21:42:47 +0000128 failfast=False, buffer=False, resultclass=None):
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000129 self.stream = _WritelnDecorator(stream)
130 self.descriptions = descriptions
131 self.verbosity = verbosity
Michael Foord1b9e9532010-03-22 01:01:34 +0000132 self.failfast = failfast
Michael Foord5637f042010-04-02 21:42:47 +0000133 self.buffer = buffer
Michael Foorddb43b5a2010-02-10 14:25:12 +0000134 if resultclass is not None:
135 self.resultclass = resultclass
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000136
137 def _makeResult(self):
Michael Foorddb43b5a2010-02-10 14:25:12 +0000138 return self.resultclass(self.stream, self.descriptions, self.verbosity)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000139
140 def run(self, test):
141 "Run the given test case or test suite."
142 result = self._makeResult()
Michael Foordfa2f1cd2010-03-26 03:18:31 +0000143 registerResult(result)
Michael Foord1b9e9532010-03-22 01:01:34 +0000144 result.failfast = self.failfast
Michael Foord5637f042010-04-02 21:42:47 +0000145 result.buffer = self.buffer
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000146 startTime = time.time()
147 startTestRun = getattr(result, 'startTestRun', None)
148 if startTestRun is not None:
149 startTestRun()
150 try:
151 test(result)
152 finally:
153 stopTestRun = getattr(result, 'stopTestRun', None)
154 if stopTestRun is not None:
155 stopTestRun()
156 stopTime = time.time()
157 timeTaken = stopTime - startTime
158 result.printErrors()
Michael Foordd99ef9a2010-02-23 17:00:53 +0000159 if hasattr(result, 'separator2'):
160 self.stream.writeln(result.separator2)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000161 run = result.testsRun
162 self.stream.writeln("Ran %d test%s in %.3fs" %
163 (run, run != 1 and "s" or "", timeTaken))
164 self.stream.writeln()
Michael Foordd99ef9a2010-02-23 17:00:53 +0000165
166 expectedFails = unexpectedSuccesses = skipped = 0
167 try:
168 results = map(len, (result.expectedFailures,
169 result.unexpectedSuccesses,
170 result.skipped))
Michael Foordd99ef9a2010-02-23 17:00:53 +0000171 except AttributeError:
172 pass
Benjamin Peterson55727e12010-11-18 14:16:32 +0000173 else:
174 expectedFails, unexpectedSuccesses, skipped = results
Michael Foordd99ef9a2010-02-23 17:00:53 +0000175
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000176 infos = []
177 if not result.wasSuccessful():
178 self.stream.write("FAILED")
179 failed, errored = map(len, (result.failures, result.errors))
180 if failed:
181 infos.append("failures=%d" % failed)
182 if errored:
183 infos.append("errors=%d" % errored)
184 else:
185 self.stream.write("OK")
186 if skipped:
187 infos.append("skipped=%d" % skipped)
188 if expectedFails:
189 infos.append("expected failures=%d" % expectedFails)
190 if unexpectedSuccesses:
191 infos.append("unexpected successes=%d" % unexpectedSuccesses)
192 if infos:
193 self.stream.writeln(" (%s)" % (", ".join(infos),))
194 else:
195 self.stream.write("\n")
196 return result