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