runner.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. #
  2. # Python unit test runner
  3. #
  4. # Author : Sander Mathijs van Veen <smvv@kompiler.org>
  5. # License: GPL version 3, see also the file `LICENSE'.
  6. #
  7. import os
  8. import sys
  9. import time
  10. import unittest
  11. class TextTestRunner(unittest.TextTestRunner):
  12. """This is a wrapper class used to minimize the amount of blank lines
  13. printed to stdout. The method ``run`` is modified and it's original source
  14. is in Python Standard Library's ``unittest`` module."""
  15. def __init__(self, stream=sys.stderr, descriptions=True, verbosity=1,
  16. color=True):
  17. unittest.TextTestRunner.__init__(self, stream, descriptions, verbosity)
  18. self.color = color
  19. def run(self, test):
  20. "Run the given test case or test suite."
  21. result = self._makeResult()
  22. result.failfast = getattr(self, 'failfast', None)
  23. result.buffer = getattr(self, 'buffer', None)
  24. startTime = time.time()
  25. startTestRun = getattr(result, 'startTestRun', None)
  26. if startTestRun is not None:
  27. startTestRun()
  28. try:
  29. test(result)
  30. finally:
  31. stopTestRun = getattr(result, 'stopTestRun', None)
  32. if stopTestRun is not None:
  33. stopTestRun()
  34. stopTime = time.time()
  35. timeTaken = stopTime - startTime
  36. result.printErrors()
  37. if not result.wasSuccessful():
  38. if self.color:
  39. msg = '\033[0;31mFAIL\033[1;m'
  40. else:
  41. msg = 'FAIL'
  42. self.stream.write(msg)
  43. else:
  44. if self.color:
  45. msg = '\033[0;32mOK\033[0;m'
  46. else:
  47. msg = 'OK'
  48. self.stream.write(msg)
  49. self.stream.write(' %s: %d test%s in %.3fs ' \
  50. % (test.filename, result.testsRun,
  51. result.testsRun != 1 and 's' or '', timeTaken))
  52. expectedFails = unexpectedSuccesses = skipped = 0
  53. try:
  54. results = map(len, (result.expectedFailures,
  55. result.unexpectedSuccesses,
  56. result.skipped))
  57. except AttributeError:
  58. pass
  59. else:
  60. expectedFails, unexpectedSuccesses, skipped = results
  61. infos = []
  62. if not result.wasSuccessful():
  63. failed, errored = map(len, (result.failures, result.errors))
  64. if failed:
  65. if self.color:
  66. msg = 'failures=\033[1;31m%d\033[1;m'
  67. else:
  68. msg = 'failures=%d'
  69. infos.append(msg % failed)
  70. if errored:
  71. if self.color:
  72. msg = 'errors=\033[1;31m%d\033[1;m'
  73. else:
  74. msg = 'errors=%d'
  75. infos.append(msg % errored)
  76. if skipped:
  77. if self.color:
  78. msg = 'skipped=\033[1;33m%d\033[1;m'
  79. else:
  80. msg = 'skipped=%d'
  81. infos.append(msg % skipped)
  82. if expectedFails:
  83. infos.append('expected failures=%d' % expectedFails)
  84. if unexpectedSuccesses:
  85. infos.append('unexpected successes=%d' % unexpectedSuccesses)
  86. if infos:
  87. self.stream.writeln(' (%s)' % (', '.join(infos),))
  88. else:
  89. self.stream.write('\n')
  90. return result
  91. def main(tests, verbose=0, color=True):
  92. testcases = []
  93. # Dynamic load the requested module containing the test cases.
  94. for testfile in tests:
  95. try:
  96. module_name = os.path.splitext(testfile)[0].replace('/', '.')
  97. module_obj = __import__(module_name)
  98. except:
  99. print 'testfile: ', testfile
  100. print 'module_name:', module_name
  101. raise
  102. # Start the test runner and display the results to stdout.
  103. try:
  104. suite_name = module_name.split('.')[-1]
  105. container = module_obj.__dict__[suite_name]
  106. except:
  107. print 'testfile: ', testfile
  108. print 'module_name:', module_name
  109. print 'module_obj: ', module_obj, dir(module_obj)
  110. raise
  111. # Convert lowercase, underscored suite name to Python class name.
  112. class_parts = suite_name[5:].split('_')
  113. class_name = 'Test' + ''.join([p.capitalize() for p in class_parts])
  114. testcase = container.__dict__[class_name]
  115. testcases += [unittest.TestLoader().loadTestsFromTestCase(testcase)]
  116. # Create the text runner and execute the tests.
  117. runner = TextTestRunner(verbosity=verbose, color=color)
  118. suite = unittest.TestSuite(testcases)
  119. suite.filename = testfile
  120. result = runner.run(suite)
  121. # Return non zero exit code if there are failures or errors occured.
  122. if result.failures or result.errors:
  123. sys.exit(1)