runner.py 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. """Running tests"""
  2. import sys
  3. import time
  4. import warnings
  5. from . import result
  6. from .signals import registerResult
  7. __unittest = True
  8. class _WritelnDecorator(object):
  9. """Used to decorate file-like objects with a handy 'writeln' method"""
  10. def __init__(self,stream):
  11. self.stream = stream
  12. def __getattr__(self, attr):
  13. if attr in ('stream', '__getstate__'):
  14. raise AttributeError(attr)
  15. return getattr(self.stream,attr)
  16. def writeln(self, arg=None):
  17. if arg:
  18. self.write(arg)
  19. self.write('\n') # text-mode streams translate to \r\n if needed
  20. class TextTestResult(result.TestResult):
  21. """A test result class that can print formatted text results to a stream.
  22. Used by TextTestRunner.
  23. """
  24. separator1 = '=' * 70
  25. separator2 = '-' * 70
  26. def __init__(self, stream, descriptions, verbosity):
  27. super(TextTestResult, self).__init__(stream, descriptions, verbosity)
  28. self.stream = stream
  29. self.showAll = verbosity > 1
  30. self.dots = verbosity == 1
  31. self.descriptions = descriptions
  32. def getDescription(self, test):
  33. doc_first_line = test.shortDescription()
  34. if self.descriptions and doc_first_line:
  35. return '\n'.join((str(test), doc_first_line))
  36. else:
  37. return str(test)
  38. def startTest(self, test):
  39. super(TextTestResult, self).startTest(test)
  40. if self.showAll:
  41. self.stream.write(self.getDescription(test))
  42. self.stream.write(" ... ")
  43. self.stream.flush()
  44. def addSuccess(self, test):
  45. super(TextTestResult, self).addSuccess(test)
  46. if self.showAll:
  47. self.stream.writeln("ok")
  48. self.stream.flush()
  49. elif self.dots:
  50. self.stream.write('.')
  51. self.stream.flush()
  52. def addError(self, test, err):
  53. super(TextTestResult, self).addError(test, err)
  54. if self.showAll:
  55. self.stream.writeln("ERROR")
  56. self.stream.flush()
  57. elif self.dots:
  58. self.stream.write('E')
  59. self.stream.flush()
  60. def addFailure(self, test, err):
  61. super(TextTestResult, self).addFailure(test, err)
  62. if self.showAll:
  63. self.stream.writeln("FAIL")
  64. self.stream.flush()
  65. elif self.dots:
  66. self.stream.write('F')
  67. self.stream.flush()
  68. def addSkip(self, test, reason):
  69. super(TextTestResult, self).addSkip(test, reason)
  70. if self.showAll:
  71. self.stream.writeln("skipped {0!r}".format(reason))
  72. self.stream.flush()
  73. elif self.dots:
  74. self.stream.write("s")
  75. self.stream.flush()
  76. def addExpectedFailure(self, test, err):
  77. super(TextTestResult, self).addExpectedFailure(test, err)
  78. if self.showAll:
  79. self.stream.writeln("expected failure")
  80. self.stream.flush()
  81. elif self.dots:
  82. self.stream.write("x")
  83. self.stream.flush()
  84. def addUnexpectedSuccess(self, test):
  85. super(TextTestResult, self).addUnexpectedSuccess(test)
  86. if self.showAll:
  87. self.stream.writeln("unexpected success")
  88. self.stream.flush()
  89. elif self.dots:
  90. self.stream.write("u")
  91. self.stream.flush()
  92. def printErrors(self):
  93. if self.dots or self.showAll:
  94. self.stream.writeln()
  95. self.stream.flush()
  96. self.printErrorList('ERROR', self.errors)
  97. self.printErrorList('FAIL', self.failures)
  98. def printErrorList(self, flavour, errors):
  99. for test, err in errors:
  100. self.stream.writeln(self.separator1)
  101. self.stream.writeln("%s: %s" % (flavour,self.getDescription(test)))
  102. self.stream.writeln(self.separator2)
  103. self.stream.writeln("%s" % err)
  104. self.stream.flush()
  105. class TextTestRunner(object):
  106. """A test runner class that displays results in textual form.
  107. It prints out the names of tests as they are run, errors as they
  108. occur, and a summary of the results at the end of the test run.
  109. """
  110. resultclass = TextTestResult
  111. def __init__(self, stream=None, descriptions=True, verbosity=1,
  112. failfast=False, buffer=False, resultclass=None, warnings=None,
  113. *, tb_locals=False):
  114. """Construct a TextTestRunner.
  115. Subclasses should accept **kwargs to ensure compatibility as the
  116. interface changes.
  117. """
  118. if stream is None:
  119. stream = sys.stderr
  120. self.stream = _WritelnDecorator(stream)
  121. self.descriptions = descriptions
  122. self.verbosity = verbosity
  123. self.failfast = failfast
  124. self.buffer = buffer
  125. self.tb_locals = tb_locals
  126. self.warnings = warnings
  127. if resultclass is not None:
  128. self.resultclass = resultclass
  129. def _makeResult(self):
  130. return self.resultclass(self.stream, self.descriptions, self.verbosity)
  131. def run(self, test):
  132. "Run the given test case or test suite."
  133. result = self._makeResult()
  134. registerResult(result)
  135. result.failfast = self.failfast
  136. result.buffer = self.buffer
  137. result.tb_locals = self.tb_locals
  138. with warnings.catch_warnings():
  139. if self.warnings:
  140. # if self.warnings is set, use it to filter all the warnings
  141. warnings.simplefilter(self.warnings)
  142. # if the filter is 'default' or 'always', special-case the
  143. # warnings from the deprecated unittest methods to show them
  144. # no more than once per module, because they can be fairly
  145. # noisy. The -Wd and -Wa flags can be used to bypass this
  146. # only when self.warnings is None.
  147. if self.warnings in ['default', 'always']:
  148. warnings.filterwarnings('module',
  149. category=DeprecationWarning,
  150. message=r'Please use assert\w+ instead.')
  151. startTime = time.perf_counter()
  152. startTestRun = getattr(result, 'startTestRun', None)
  153. if startTestRun is not None:
  154. startTestRun()
  155. try:
  156. test(result)
  157. finally:
  158. stopTestRun = getattr(result, 'stopTestRun', None)
  159. if stopTestRun is not None:
  160. stopTestRun()
  161. stopTime = time.perf_counter()
  162. timeTaken = stopTime - startTime
  163. result.printErrors()
  164. if hasattr(result, 'separator2'):
  165. self.stream.writeln(result.separator2)
  166. run = result.testsRun
  167. self.stream.writeln("Ran %d test%s in %.3fs" %
  168. (run, run != 1 and "s" or "", timeTaken))
  169. self.stream.writeln()
  170. expectedFails = unexpectedSuccesses = skipped = 0
  171. try:
  172. results = map(len, (result.expectedFailures,
  173. result.unexpectedSuccesses,
  174. result.skipped))
  175. except AttributeError:
  176. pass
  177. else:
  178. expectedFails, unexpectedSuccesses, skipped = results
  179. infos = []
  180. if not result.wasSuccessful():
  181. self.stream.write("FAILED")
  182. failed, errored = len(result.failures), len(result.errors)
  183. if failed:
  184. infos.append("failures=%d" % failed)
  185. if errored:
  186. infos.append("errors=%d" % errored)
  187. else:
  188. self.stream.write("OK")
  189. if skipped:
  190. infos.append("skipped=%d" % skipped)
  191. if expectedFails:
  192. infos.append("expected failures=%d" % expectedFails)
  193. if unexpectedSuccesses:
  194. infos.append("unexpected successes=%d" % unexpectedSuccesses)
  195. if infos:
  196. self.stream.writeln(" (%s)" % (", ".join(infos),))
  197. else:
  198. self.stream.write("\n")
  199. self.stream.flush()
  200. return result