blob: 8473a33795a6b20900674dbcecd389316bb288a2 [file] [log] [blame]
Benjamin Petersonbed7d042009-07-19 21:01:52 +00001"""Unittest main program"""
2
3import sys
4import os
5import types
6
7from . import loader, runner
Michael Foord65b69a12010-03-27 13:25:41 +00008from .signals import installHandler
Benjamin Petersonbed7d042009-07-19 21:01:52 +00009
Benjamin Petersondccc1fc2010-03-22 00:15:53 +000010__unittest = True
11
Benjamin Petersonb48af542010-04-11 20:43:16 +000012FAILFAST = " -f, --failfast Stop on first failure\n"
13CATCHBREAK = " -c, --catch Catch control-C and display results\n"
14BUFFEROUTPUT = " -b, --buffer Buffer stdout and stderr during test runs\n"
Michael Foord65b69a12010-03-27 13:25:41 +000015
Benjamin Petersonbed7d042009-07-19 21:01:52 +000016USAGE_AS_MAIN = """\
17Usage: %(progName)s [options] [tests]
18
19Options:
20 -h, --help Show this message
21 -v, --verbose Verbose output
22 -q, --quiet Minimal output
Benjamin Petersonb48af542010-04-11 20:43:16 +000023%(failfast)s%(catchbreak)s%(buffer)s
Benjamin Petersonbed7d042009-07-19 21:01:52 +000024Examples:
Michael Foordf707aa72010-05-10 20:23:58 +000025 %(progName)s test_module - run tests from test_module
26 %(progName)s module.TestClass - run tests from module.TestClass
27 %(progName)s module.Class.test_method - run specified test method
Benjamin Petersonbed7d042009-07-19 21:01:52 +000028
29[tests] can be a list of any number of test modules, classes and test
30methods.
31
32Alternative Usage: %(progName)s discover [options]
33
34Options:
35 -v, --verbose Verbose output
Benjamin Petersonb48af542010-04-11 20:43:16 +000036%(failfast)s%(catchbreak)s%(buffer)s -s directory Directory to start discovery ('.' default)
Benjamin Petersonbed7d042009-07-19 21:01:52 +000037 -p pattern Pattern to match test files ('test*.py' default)
38 -t directory Top level directory of project (default to
39 start directory)
40
41For test discovery all test modules must be importable from the top
42level directory of the project.
43"""
44
45USAGE_FROM_MODULE = """\
46Usage: %(progName)s [options] [test] [...]
47
48Options:
49 -h, --help Show this message
50 -v, --verbose Verbose output
51 -q, --quiet Minimal output
Benjamin Petersonb48af542010-04-11 20:43:16 +000052%(failfast)s%(catchbreak)s%(buffer)s
Benjamin Petersonbed7d042009-07-19 21:01:52 +000053Examples:
54 %(progName)s - run default set of tests
55 %(progName)s MyTestSuite - run suite 'MyTestSuite'
56 %(progName)s MyTestCase.testSomething - run MyTestCase.testSomething
57 %(progName)s MyTestCase - run all 'test*' test methods
58 in MyTestCase
59"""
60
Michael Foord65b69a12010-03-27 13:25:41 +000061
62
Benjamin Petersonbed7d042009-07-19 21:01:52 +000063class TestProgram(object):
64 """A command-line program that runs a set of tests; this is primarily
65 for making test modules conveniently executable.
66 """
Benjamin Petersoneab4b4c2010-03-22 02:53:52 +000067 USAGE = USAGE_FROM_MODULE
Michael Foord65b69a12010-03-27 13:25:41 +000068
69 # defaults for testing
Michael Foordf707aa72010-05-10 20:23:58 +000070 failfast = catchbreak = buffer = progName = None
Michael Foord65b69a12010-03-27 13:25:41 +000071
Michael Foord4a8cf3c2010-05-07 15:35:24 +000072 def __init__(self, module='__main__', defaultTest=None, argv=None,
73 testRunner=None, testLoader=loader.defaultTestLoader,
74 exit=True, verbosity=1, failfast=None, catchbreak=None,
75 buffer=None):
Benjamin Petersonbed7d042009-07-19 21:01:52 +000076 if isinstance(module, str):
77 self.module = __import__(module)
78 for part in module.split('.')[1:]:
79 self.module = getattr(self.module, part)
80 else:
81 self.module = module
82 if argv is None:
83 argv = sys.argv
84
85 self.exit = exit
Benjamin Peterson8769fd82010-03-22 01:13:48 +000086 self.failfast = failfast
Michael Foord65b69a12010-03-27 13:25:41 +000087 self.catchbreak = catchbreak
Benjamin Petersonbed7d042009-07-19 21:01:52 +000088 self.verbosity = verbosity
Benjamin Petersonb48af542010-04-11 20:43:16 +000089 self.buffer = buffer
Benjamin Petersonbed7d042009-07-19 21:01:52 +000090 self.defaultTest = defaultTest
91 self.testRunner = testRunner
92 self.testLoader = testLoader
93 self.progName = os.path.basename(argv[0])
94 self.parseArgs(argv)
95 self.runTests()
96
97 def usageExit(self, msg=None):
98 if msg:
99 print(msg)
Benjamin Petersonb48af542010-04-11 20:43:16 +0000100 usage = {'progName': self.progName, 'catchbreak': '', 'failfast': '',
101 'buffer': ''}
Michael Foord65b69a12010-03-27 13:25:41 +0000102 if self.failfast != False:
103 usage['failfast'] = FAILFAST
104 if self.catchbreak != False:
105 usage['catchbreak'] = CATCHBREAK
Benjamin Petersonb48af542010-04-11 20:43:16 +0000106 if self.buffer != False:
107 usage['buffer'] = BUFFEROUTPUT
Michael Foord65b69a12010-03-27 13:25:41 +0000108 print(self.USAGE % usage)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000109 sys.exit(2)
110
111 def parseArgs(self, argv):
Michael Foord086f3082010-11-21 21:28:01 +0000112 if ((len(argv) > 1 and argv[1].lower() == 'discover') or
113 (len(argv) == 1 and self.module is None)):
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000114 self._do_discovery(argv[2:])
115 return
116
117 import getopt
Benjamin Petersonb48af542010-04-11 20:43:16 +0000118 long_opts = ['help', 'verbose', 'quiet', 'failfast', 'catch', 'buffer']
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000119 try:
Benjamin Petersonb48af542010-04-11 20:43:16 +0000120 options, args = getopt.getopt(argv[1:], 'hHvqfcb', long_opts)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000121 for opt, value in options:
122 if opt in ('-h','-H','--help'):
123 self.usageExit()
124 if opt in ('-q','--quiet'):
125 self.verbosity = 0
126 if opt in ('-v','--verbose'):
127 self.verbosity = 2
Benjamin Peterson8769fd82010-03-22 01:13:48 +0000128 if opt in ('-f','--failfast'):
Michael Foord65b69a12010-03-27 13:25:41 +0000129 if self.failfast is None:
130 self.failfast = True
131 # Should this raise an exception if -f is not valid?
132 if opt in ('-c','--catch'):
133 if self.catchbreak is None:
134 self.catchbreak = True
135 # Should this raise an exception if -c is not valid?
Benjamin Petersonb48af542010-04-11 20:43:16 +0000136 if opt in ('-b','--buffer'):
137 if self.buffer is None:
138 self.buffer = True
139 # Should this raise an exception if -b is not valid?
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000140 if len(args) == 0 and self.defaultTest is None:
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +0000141 # createTests will load tests from self.module
142 self.testNames = None
143 elif len(args) > 0:
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000144 self.testNames = args
145 if __name__ == '__main__':
146 # to support python -m unittest ...
147 self.module = None
148 else:
149 self.testNames = (self.defaultTest,)
150 self.createTests()
151 except getopt.error as msg:
152 self.usageExit(msg)
153
154 def createTests(self):
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +0000155 if self.testNames is None:
156 self.test = self.testLoader.loadTestsFromModule(self.module)
157 else:
158 self.test = self.testLoader.loadTestsFromNames(self.testNames,
159 self.module)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000160
161 def _do_discovery(self, argv, Loader=loader.TestLoader):
162 # handle command line args for test discovery
Michael Foordf707aa72010-05-10 20:23:58 +0000163 self.progName = '%s discover' % self.progName
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000164 import optparse
165 parser = optparse.OptionParser()
Michael Foordf707aa72010-05-10 20:23:58 +0000166 parser.prog = self.progName
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000167 parser.add_option('-v', '--verbose', dest='verbose', default=False,
168 help='Verbose output', action='store_true')
Michael Foord65b69a12010-03-27 13:25:41 +0000169 if self.failfast != False:
170 parser.add_option('-f', '--failfast', dest='failfast', default=False,
171 help='Stop on first fail or error',
172 action='store_true')
173 if self.catchbreak != False:
174 parser.add_option('-c', '--catch', dest='catchbreak', default=False,
175 help='Catch ctrl-C and display results so far',
176 action='store_true')
Benjamin Petersonb48af542010-04-11 20:43:16 +0000177 if self.buffer != False:
178 parser.add_option('-b', '--buffer', dest='buffer', default=False,
179 help='Buffer stdout and stderr during tests',
180 action='store_true')
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000181 parser.add_option('-s', '--start-directory', dest='start', default='.',
182 help="Directory to start discovery ('.' default)")
183 parser.add_option('-p', '--pattern', dest='pattern', default='test*.py',
184 help="Pattern to match tests ('test*.py' default)")
185 parser.add_option('-t', '--top-level-directory', dest='top', default=None,
186 help='Top level directory of project (defaults to start directory)')
187
188 options, args = parser.parse_args(argv)
189 if len(args) > 3:
190 self.usageExit()
191
192 for name, value in zip(('start', 'pattern', 'top'), args):
193 setattr(options, name, value)
194
Michael Foord65b69a12010-03-27 13:25:41 +0000195 # only set options from the parsing here
196 # if they weren't set explicitly in the constructor
197 if self.failfast is None:
198 self.failfast = options.failfast
199 if self.catchbreak is None:
200 self.catchbreak = options.catchbreak
Benjamin Petersonb48af542010-04-11 20:43:16 +0000201 if self.buffer is None:
202 self.buffer = options.buffer
Michael Foord65b69a12010-03-27 13:25:41 +0000203
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000204 if options.verbose:
205 self.verbosity = 2
206
207 start_dir = options.start
208 pattern = options.pattern
209 top_level_dir = options.top
210
211 loader = Loader()
212 self.test = loader.discover(start_dir, pattern, top_level_dir)
213
214 def runTests(self):
Michael Foord65b69a12010-03-27 13:25:41 +0000215 if self.catchbreak:
216 installHandler()
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000217 if self.testRunner is None:
218 self.testRunner = runner.TextTestRunner
219 if isinstance(self.testRunner, type):
220 try:
Benjamin Peterson8769fd82010-03-22 01:13:48 +0000221 testRunner = self.testRunner(verbosity=self.verbosity,
Benjamin Petersonb48af542010-04-11 20:43:16 +0000222 failfast=self.failfast,
223 buffer=self.buffer)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000224 except TypeError:
Benjamin Petersonb48af542010-04-11 20:43:16 +0000225 # didn't accept the verbosity, buffer or failfast arguments
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000226 testRunner = self.testRunner()
227 else:
228 # it is assumed to be a TestRunner instance
229 testRunner = self.testRunner
230 self.result = testRunner.run(self.test)
231 if self.exit:
232 sys.exit(not self.result.wasSuccessful())
233
234main = TestProgram