runner.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  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. self.stream.write('%s: %d test%s in %.3fs ' \
  38. % (test.filename, result.testsRun,
  39. result.testsRun != 1 and 's' or '', timeTaken))
  40. expectedFails = unexpectedSuccesses = skipped = 0
  41. try:
  42. results = map(len, (result.expectedFailures,
  43. result.unexpectedSuccesses,
  44. result.skipped))
  45. except AttributeError:
  46. pass
  47. else:
  48. expectedFails, unexpectedSuccesses, skipped = results
  49. infos = []
  50. if not result.wasSuccessful():
  51. if self.color:
  52. msg = '\033[0;31mFAILED\033[1;m'
  53. else:
  54. msg = 'FAILED'
  55. self.stream.write(msg)
  56. failed, errored = map(len, (result.failures, result.errors))
  57. if failed:
  58. if self.color:
  59. msg = 'failures=\033[1;31m%d\033[1;m'
  60. else:
  61. msg = 'failures=%d'
  62. infos.append(msg % failed)
  63. if errored:
  64. if self.color:
  65. msg = 'errors=\033[1;31m%d\033[1;m'
  66. else:
  67. msg = 'errors=%d'
  68. infos.append(msg % errored)
  69. else:
  70. if self.color:
  71. msg = '\033[0;32mOK\033[0;m'
  72. else:
  73. msg = 'OK'
  74. self.stream.write(msg)
  75. if skipped:
  76. if self.color:
  77. msg = 'skipped=\033[1;33m%d\033[1;m'
  78. else:
  79. msg = 'skipped=%d'
  80. infos.append(msg % skipped)
  81. if expectedFails:
  82. infos.append('expected failures=%d' % expectedFails)
  83. if unexpectedSuccesses:
  84. infos.append('unexpected successes=%d' % unexpectedSuccesses)
  85. if infos:
  86. self.stream.writeln(' (%s)' % (', '.join(infos),))
  87. else:
  88. self.stream.write('\n')
  89. return result
  90. def main(tests, verbose=0, color=True):
  91. testcases = []
  92. # Dynamic load the requested module containing the test cases.
  93. for testfile in tests:
  94. try:
  95. module_name = os.path.splitext(testfile)[0].replace('/', '.')
  96. module_obj = __import__(module_name)
  97. except:
  98. print 'testfile: ', testfile
  99. print 'module_name:', module_name
  100. raise
  101. # Start the test runner and display the results to stdout.
  102. try:
  103. suite_name = module_name.split('.')[-1]
  104. container = module_obj.__dict__[suite_name]
  105. except:
  106. print 'testfile: ', testfile
  107. print 'module_name:', module_name
  108. print 'module_obj: ', module_obj, dir(module_obj)
  109. raise
  110. # Convert lowercase, underscored suite name to Python class name.
  111. class_parts = suite_name[5:].split('_')
  112. class_name = 'Test' + ''.join([p.capitalize() for p in class_parts])
  113. testcase = container.__dict__[class_name]
  114. testcases += [unittest.TestLoader().loadTestsFromTestCase(testcase)]
  115. # Create the text runner and execute the tests.
  116. runner = TextTestRunner(verbosity=verbose, color=color)
  117. suite = unittest.TestSuite(testcases)
  118. suite.filename = testfile
  119. result = runner.run(suite)
  120. # Return non zero exit code if there are failures or errors occured.
  121. if result.failures or result.errors:
  122. sys.exit(1)