1"""Running tests""" 2 3import sys 4import time 5import warnings 6 7from . import result 8from .signals import registerResult 9 10__unittest = True 11 12 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): 19 if attr in ('stream', '__getstate__'): 20 raise AttributeError(attr) 21 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 29class TextTestResult(result.TestResult): 30 """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): 38 super(TextTestResult, self).__init__(stream, descriptions, verbosity) 39 self.stream = stream 40 self.showAll = verbosity > 1 41 self.dots = verbosity == 1 42 self.descriptions = descriptions 43 44 def getDescription(self, test): 45 doc_first_line = test.shortDescription() 46 if self.descriptions and doc_first_line: 47 return '\n'.join((str(test), doc_first_line)) 48 else: 49 return str(test) 50 51 def startTest(self, test): 52 super(TextTestResult, self).startTest(test) 53 if self.showAll: 54 self.stream.write(self.getDescription(test)) 55 self.stream.write(" ... ") 56 self.stream.flush() 57 58 def addSuccess(self, test): 59 super(TextTestResult, self).addSuccess(test) 60 if self.showAll: 61 self.stream.writeln("ok") 62 self.stream.flush() 63 elif self.dots: 64 self.stream.write('.') 65 self.stream.flush() 66 67 def addError(self, test, err): 68 super(TextTestResult, self).addError(test, err) 69 if self.showAll: 70 self.stream.writeln("ERROR") 71 self.stream.flush() 72 elif self.dots: 73 self.stream.write('E') 74 self.stream.flush() 75 76 def addFailure(self, test, err): 77 super(TextTestResult, self).addFailure(test, err) 78 if self.showAll: 79 self.stream.writeln("FAIL") 80 self.stream.flush() 81 elif self.dots: 82 self.stream.write('F') 83 self.stream.flush() 84 85 def addSkip(self, test, reason): 86 super(TextTestResult, self).addSkip(test, reason) 87 if self.showAll: 88 self.stream.writeln("skipped {0!r}".format(reason)) 89 self.stream.flush() 90 elif self.dots: 91 self.stream.write("s") 92 self.stream.flush() 93 94 def addExpectedFailure(self, test, err): 95 super(TextTestResult, self).addExpectedFailure(test, err) 96 if self.showAll: 97 self.stream.writeln("expected failure") 98 self.stream.flush() 99 elif self.dots: 100 self.stream.write("x") 101 self.stream.flush() 102 103 def addUnexpectedSuccess(self, test): 104 super(TextTestResult, self).addUnexpectedSuccess(test) 105 if self.showAll: 106 self.stream.writeln("unexpected success") 107 self.stream.flush() 108 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() 115 self.stream.flush() 116 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) 125 self.stream.flush() 126 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 """ 134 resultclass = TextTestResult 135 136 def __init__(self, stream=None, descriptions=True, verbosity=1, 137 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 """ 144 if stream is None: 145 stream = sys.stderr 146 self.stream = _WritelnDecorator(stream) 147 self.descriptions = descriptions 148 self.verbosity = verbosity 149 self.failfast = failfast 150 self.buffer = buffer 151 self.tb_locals = tb_locals 152 self.warnings = warnings 153 if resultclass is not None: 154 self.resultclass = resultclass 155 156 def _makeResult(self): 157 return self.resultclass(self.stream, self.descriptions, self.verbosity) 158 159 def run(self, test): 160 "Run the given test case or test suite." 161 result = self._makeResult() 162 registerResult(result) 163 result.failfast = self.failfast 164 result.buffer = self.buffer 165 result.tb_locals = self.tb_locals 166 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, 178 message=r'Please use assert\w+ instead.') 179 startTime = time.perf_counter() 180 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() 189 stopTime = time.perf_counter() 190 timeTaken = stopTime - startTime 191 result.printErrors() 192 if hasattr(result, 'separator2'): 193 self.stream.writeln(result.separator2) 194 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() 198 199 expectedFails = unexpectedSuccesses = skipped = 0 200 try: 201 results = map(len, (result.expectedFailures, 202 result.unexpectedSuccesses, 203 result.skipped)) 204 except AttributeError: 205 pass 206 else: 207 expectedFails, unexpectedSuccesses, skipped = results 208 209 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") 229 self.stream.flush() 230 return result 231