main.py 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. """Unittest main program"""
  2. import sys
  3. import os
  4. import types
  5. from . import loader, runner
  6. from .signals import installHandler
  7. __unittest = True
  8. FAILFAST = " -f, --failfast Stop on first failure\n"
  9. CATCHBREAK = " -c, --catch Catch control-C and display results\n"
  10. BUFFEROUTPUT = " -b, --buffer Buffer stdout and stderr during test runs\n"
  11. USAGE_AS_MAIN = """\
  12. Usage: %(progName)s [options] [tests]
  13. Options:
  14. -h, --help Show this message
  15. -v, --verbose Verbose output
  16. -q, --quiet Minimal output
  17. %(failfast)s%(catchbreak)s%(buffer)s
  18. Examples:
  19. %(progName)s test_module - run tests from test_module
  20. %(progName)s module.TestClass - run tests from module.TestClass
  21. %(progName)s module.Class.test_method - run specified test method
  22. [tests] can be a list of any number of test modules, classes and test
  23. methods.
  24. Alternative Usage: %(progName)s discover [options]
  25. Options:
  26. -v, --verbose Verbose output
  27. %(failfast)s%(catchbreak)s%(buffer)s -s directory Directory to start discovery ('.' default)
  28. -p pattern Pattern to match test files ('test*.py' default)
  29. -t directory Top level directory of project (default to
  30. start directory)
  31. For test discovery all test modules must be importable from the top
  32. level directory of the project.
  33. """
  34. USAGE_FROM_MODULE = """\
  35. Usage: %(progName)s [options] [test] [...]
  36. Options:
  37. -h, --help Show this message
  38. -v, --verbose Verbose output
  39. -q, --quiet Minimal output
  40. %(failfast)s%(catchbreak)s%(buffer)s
  41. Examples:
  42. %(progName)s - run default set of tests
  43. %(progName)s MyTestSuite - run suite 'MyTestSuite'
  44. %(progName)s MyTestCase.testSomething - run MyTestCase.testSomething
  45. %(progName)s MyTestCase - run all 'test*' test methods
  46. in MyTestCase
  47. """
  48. class TestProgram(object):
  49. """A command-line program that runs a set of tests; this is primarily
  50. for making test modules conveniently executable.
  51. """
  52. USAGE = USAGE_FROM_MODULE
  53. # defaults for testing
  54. failfast = catchbreak = buffer = progName = None
  55. def __init__(self, module='__main__', defaultTest=None, argv=None,
  56. testRunner=None, testLoader=loader.defaultTestLoader,
  57. exit=True, verbosity=1, failfast=None, catchbreak=None,
  58. buffer=None):
  59. if isinstance(module, basestring):
  60. self.module = __import__(module)
  61. for part in module.split('.')[1:]:
  62. self.module = getattr(self.module, part)
  63. else:
  64. self.module = module
  65. if argv is None:
  66. argv = sys.argv
  67. self.exit = exit
  68. self.failfast = failfast
  69. self.catchbreak = catchbreak
  70. self.verbosity = verbosity
  71. self.buffer = buffer
  72. self.defaultTest = defaultTest
  73. self.testRunner = testRunner
  74. self.testLoader = testLoader
  75. self.progName = os.path.basename(argv[0])
  76. self.parseArgs(argv)
  77. self.runTests()
  78. def usageExit(self, msg=None):
  79. if msg:
  80. print msg
  81. usage = {'progName': self.progName, 'catchbreak': '', 'failfast': '',
  82. 'buffer': ''}
  83. if self.failfast != False:
  84. usage['failfast'] = FAILFAST
  85. if self.catchbreak != False:
  86. usage['catchbreak'] = CATCHBREAK
  87. if self.buffer != False:
  88. usage['buffer'] = BUFFEROUTPUT
  89. print self.USAGE % usage
  90. sys.exit(2)
  91. def parseArgs(self, argv):
  92. if len(argv) > 1 and argv[1].lower() == 'discover':
  93. self._do_discovery(argv[2:])
  94. return
  95. import getopt
  96. long_opts = ['help', 'verbose', 'quiet', 'failfast', 'catch', 'buffer']
  97. try:
  98. options, args = getopt.getopt(argv[1:], 'hHvqfcb', long_opts)
  99. for opt, value in options:
  100. if opt in ('-h','-H','--help'):
  101. self.usageExit()
  102. if opt in ('-q','--quiet'):
  103. self.verbosity = 0
  104. if opt in ('-v','--verbose'):
  105. self.verbosity = 2
  106. if opt in ('-f','--failfast'):
  107. if self.failfast is None:
  108. self.failfast = True
  109. # Should this raise an exception if -f is not valid?
  110. if opt in ('-c','--catch'):
  111. if self.catchbreak is None:
  112. self.catchbreak = True
  113. # Should this raise an exception if -c is not valid?
  114. if opt in ('-b','--buffer'):
  115. if self.buffer is None:
  116. self.buffer = True
  117. # Should this raise an exception if -b is not valid?
  118. if len(args) == 0 and self.defaultTest is None:
  119. # createTests will load tests from self.module
  120. self.testNames = None
  121. elif len(args) > 0:
  122. self.testNames = args
  123. if __name__ == '__main__':
  124. # to support python -m unittest ...
  125. self.module = None
  126. else:
  127. self.testNames = (self.defaultTest,)
  128. self.createTests()
  129. except getopt.error, msg:
  130. self.usageExit(msg)
  131. def createTests(self):
  132. if self.testNames is None:
  133. self.test = self.testLoader.loadTestsFromModule(self.module)
  134. else:
  135. self.test = self.testLoader.loadTestsFromNames(self.testNames,
  136. self.module)
  137. def _do_discovery(self, argv, Loader=None):
  138. if Loader is None:
  139. Loader = lambda: self.testLoader
  140. # handle command line args for test discovery
  141. self.progName = '%s discover' % self.progName
  142. import optparse
  143. parser = optparse.OptionParser()
  144. parser.prog = self.progName
  145. parser.add_option('-v', '--verbose', dest='verbose', default=False,
  146. help='Verbose output', action='store_true')
  147. if self.failfast != False:
  148. parser.add_option('-f', '--failfast', dest='failfast', default=False,
  149. help='Stop on first fail or error',
  150. action='store_true')
  151. if self.catchbreak != False:
  152. parser.add_option('-c', '--catch', dest='catchbreak', default=False,
  153. help='Catch Ctrl-C and display results so far',
  154. action='store_true')
  155. if self.buffer != False:
  156. parser.add_option('-b', '--buffer', dest='buffer', default=False,
  157. help='Buffer stdout and stderr during tests',
  158. action='store_true')
  159. parser.add_option('-s', '--start-directory', dest='start', default='.',
  160. help="Directory to start discovery ('.' default)")
  161. parser.add_option('-p', '--pattern', dest='pattern', default='test*.py',
  162. help="Pattern to match tests ('test*.py' default)")
  163. parser.add_option('-t', '--top-level-directory', dest='top', default=None,
  164. help='Top level directory of project (defaults to start directory)')
  165. options, args = parser.parse_args(argv)
  166. if len(args) > 3:
  167. self.usageExit()
  168. for name, value in zip(('start', 'pattern', 'top'), args):
  169. setattr(options, name, value)
  170. # only set options from the parsing here
  171. # if they weren't set explicitly in the constructor
  172. if self.failfast is None:
  173. self.failfast = options.failfast
  174. if self.catchbreak is None:
  175. self.catchbreak = options.catchbreak
  176. if self.buffer is None:
  177. self.buffer = options.buffer
  178. if options.verbose:
  179. self.verbosity = 2
  180. start_dir = options.start
  181. pattern = options.pattern
  182. top_level_dir = options.top
  183. loader = Loader()
  184. self.test = loader.discover(start_dir, pattern, top_level_dir)
  185. def runTests(self):
  186. if self.catchbreak:
  187. installHandler()
  188. if self.testRunner is None:
  189. self.testRunner = runner.TextTestRunner
  190. if isinstance(self.testRunner, (type, types.ClassType)):
  191. try:
  192. testRunner = self.testRunner(verbosity=self.verbosity,
  193. failfast=self.failfast,
  194. buffer=self.buffer)
  195. except TypeError:
  196. # didn't accept the verbosity, buffer or failfast arguments
  197. testRunner = self.testRunner()
  198. else:
  199. # it is assumed to be a TestRunner instance
  200. testRunner = self.testRunner
  201. self.result = testRunner.run(self.test)
  202. if self.exit:
  203. sys.exit(not self.result.wasSuccessful())
  204. main = TestProgram