1"""Running tests""" 2 3import sys 4import time 5import unittest 6import progress 7 8from unittest2 import result 9 10try: 11 from unittest2.signals import registerResult 12except ImportError: 13 def registerResult(_): 14 pass 15 16__unittest = True 17 18 19class _WritelnDecorator(object): 20 """Used to decorate file-like objects with a handy 'writeln' method""" 21 22 def __init__(self, stream): 23 self.stream = stream 24 25 def __getattr__(self, attr): 26 if attr in ('stream', '__getstate__'): 27 raise AttributeError(attr) 28 return getattr(self.stream, attr) 29 30 def writeln(self, arg=None): 31 if arg: 32 self.write(arg) 33 self.write('\n') # text-mode streams translate to \r\n if needed 34 35 36class TextTestResult(result.TestResult): 37 """A test result class that can print formatted text results to a stream. 38 39 Used by TextTestRunner. 40 """ 41 separator1 = '=' * 70 42 separator2 = '-' * 70 43 44 def __init__(self, stream, descriptions, verbosity): 45 super(TextTestResult, self).__init__() 46 self.stream = stream 47 self.showAll = verbosity > 1 48 self.dots = verbosity == 1 49 self.descriptions = descriptions 50 self.progressbar = None 51 52 if self.dots: 53 self.stream.writeln( 54 ".=success F=fail E=error s=skipped x=expected-fail u=unexpected-success") 55 self.stream.writeln("") 56 self.stream.flush() 57 58 def getDescription(self, test): 59 doc_first_line = test.shortDescription() 60 if self.descriptions and doc_first_line: 61 return '\n'.join((str(test), doc_first_line)) 62 else: 63 return str(test) 64 65 def startTest(self, test): 66 super(TextTestResult, self).startTest(test) 67 if self.showAll: 68 self.stream.write(self.getDescription(test)) 69 self.stream.write(" ... ") 70 self.stream.flush() 71 72 def newTestResult(self, test, result_short, result_long): 73 if self.showAll: 74 self.stream.writeln(result_long) 75 elif self.progressbar: 76 self.progressbar.__add__(1) 77 self.progressbar.add_event(result_short) 78 self.progressbar.show_progress() 79 elif self.dots: 80 self.stream.write(result_short) 81 self.stream.flush() 82 83 def addSuccess(self, test): 84 super(TextTestResult, self).addSuccess(test) 85 if self.progressbar: 86 self.newTestResult(test, "ok", "ok") 87 else: 88 self.newTestResult(test, ".", "ok") 89 90 def addError(self, test, err): 91 super(TextTestResult, self).addError(test, err) 92 self.newTestResult(test, "E", "ERROR") 93 94 def addFailure(self, test, err): 95 super(TextTestResult, self).addFailure(test, err) 96 self.newTestResult(test, "F", "FAILURE") 97 98 def addSkip(self, test, reason): 99 super(TextTestResult, self).addSkip(test, reason) 100 self.newTestResult(test, "s", "skipped %r" % (reason,)) 101 102 def addExpectedFailure(self, test, err, bugnumber): 103 super(TextTestResult, self).addExpectedFailure(test, err, bugnumber) 104 self.newTestResult(test, "x", "expected failure") 105 106 def addUnexpectedSuccess(self, test, bugnumber): 107 super(TextTestResult, self).addUnexpectedSuccess(test, bugnumber) 108 self.newTestResult(test, "u", "unexpected success") 109 110 def printErrors(self): 111 if self.progressbar: 112 self.progressbar.complete() 113 self.progressbar.show_progress() 114 if self.dots or self.showAll: 115 self.stream.writeln() 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" % 123 (flavour, self.getDescription(test))) 124 self.stream.writeln(self.separator2) 125 self.stream.writeln("%s" % err) 126 127 def stopTestRun(self): 128 super(TextTestResult, self).stopTestRun() 129 self.printErrors() 130 131 132class TextTestRunner(unittest.TextTestRunner): 133 """A test runner class that displays results in textual form. 134 135 It prints out the names of tests as they are run, errors as they 136 occur, and a summary of the results at the end of the test run. 137 """ 138 resultclass = TextTestResult 139 140 def __init__(self, stream=sys.stderr, descriptions=True, verbosity=1, 141 failfast=False, buffer=False, resultclass=None): 142 self.stream = _WritelnDecorator(stream) 143 self.descriptions = descriptions 144 self.verbosity = verbosity 145 self.failfast = failfast 146 self.buffer = buffer 147 if resultclass is not None: 148 self.resultclass = resultclass 149 150 def _makeResult(self): 151 return self.resultclass(self.stream, self.descriptions, self.verbosity) 152 153 def run(self, test): 154 "Run the given test case or test suite." 155 result = self._makeResult() 156 result.failfast = self.failfast 157 result.buffer = self.buffer 158 registerResult(result) 159 160 startTime = time.time() 161 startTestRun = getattr(result, 'startTestRun', None) 162 if startTestRun is not None: 163 startTestRun() 164 try: 165 test(result) 166 finally: 167 stopTestRun = getattr(result, 'stopTestRun', None) 168 if stopTestRun is not None: 169 stopTestRun() 170 else: 171 result.printErrors() 172 stopTime = time.time() 173 timeTaken = stopTime - startTime 174 if hasattr(result, 'separator2'): 175 self.stream.writeln(result.separator2) 176 run = result.testsRun 177 self.stream.writeln("Ran %d test%s in %.3fs" % 178 (run, run != 1 and "s" or "", timeTaken)) 179 self.stream.writeln() 180 181 expectedFails = unexpectedSuccesses = skipped = passed = failed = errored = 0 182 try: 183 results = map(len, (result.expectedFailures, 184 result.unexpectedSuccesses, 185 result.skipped, 186 result.passes, 187 result.failures, 188 result.errors)) 189 expectedFails, unexpectedSuccesses, skipped, passed, failed, errored = results 190 except AttributeError: 191 pass 192 infos = [] 193 infos.append("%d passes" % passed) 194 infos.append("%d failures" % failed) 195 infos.append("%d errors" % errored) 196 infos.append("%d skipped" % skipped) 197 infos.append("%d expected failures" % expectedFails) 198 infos.append("%d unexpected successes" % unexpectedSuccesses) 199 self.stream.write("RESULT: ") 200 if not result.wasSuccessful(): 201 self.stream.write("FAILED") 202 else: 203 self.stream.write("PASSED") 204 205 self.stream.writeln(" (%s)" % (", ".join(infos),)) 206 return result 207