blob: b25367992de8ac7e004c906d9b6a104f83dffb80 [file] [log] [blame]
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +00001"""Unittest main program"""
2
3import sys
4import os
5import types
6
7from . import loader, runner
Michael Foordfa2f1cd2010-03-26 03:18:31 +00008from .signals import installHandler
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +00009
Michael Foordb1aa30f2010-03-22 00:06:30 +000010__unittest = True
11
Michael Foordd43b63f2010-04-03 14:52:18 +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 Foordfa2f1cd2010-03-26 03:18:31 +000015
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +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
Michael Foordd43b63f2010-04-03 14:52:18 +000023%(failfast)s%(catchbreak)s%(buffer)s
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000024Examples:
Michael Foord72b19772010-05-10 20:21:16 +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 Petersond7b0eeb2009-07-19 20:18:21 +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
Michael Foordd43b63f2010-04-03 14:52:18 +000036%(failfast)s%(catchbreak)s%(buffer)s -s directory Directory to start discovery ('.' default)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +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
Michael Foordd43b63f2010-04-03 14:52:18 +000052%(failfast)s%(catchbreak)s%(buffer)s
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +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 Foordfa2f1cd2010-03-26 03:18:31 +000061
62
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +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 """
Michael Foordeef159b2010-03-22 02:49:08 +000067 USAGE = USAGE_FROM_MODULE
Michael Foordfa2f1cd2010-03-26 03:18:31 +000068
69 # defaults for testing
Michael Foord72b19772010-05-10 20:21:16 +000070 failfast = catchbreak = buffer = progName = None
Michael Foordfa2f1cd2010-03-26 03:18:31 +000071
Michael Foord215d3942010-05-07 15:34:08 +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 Petersond7b0eeb2009-07-19 20:18:21 +000076 if isinstance(module, basestring):
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
Michael Foord1b9e9532010-03-22 01:01:34 +000086 self.failfast = failfast
Michael Foordfa2f1cd2010-03-26 03:18:31 +000087 self.catchbreak = catchbreak
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000088 self.verbosity = verbosity
Michael Foord5637f042010-04-02 21:42:47 +000089 self.buffer = buffer
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +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
Michael Foord3dd9f402010-04-03 15:20:00 +0000100 usage = {'progName': self.progName, 'catchbreak': '', 'failfast': '',
101 'buffer': ''}
Michael Foordfa2f1cd2010-03-26 03:18:31 +0000102 if self.failfast != False:
103 usage['failfast'] = FAILFAST
104 if self.catchbreak != False:
105 usage['catchbreak'] = CATCHBREAK
Michael Foordd43b63f2010-04-03 14:52:18 +0000106 if self.buffer != False:
107 usage['buffer'] = BUFFEROUTPUT
Michael Foordfa2f1cd2010-03-26 03:18:31 +0000108 print self.USAGE % usage
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000109 sys.exit(2)
110
111 def parseArgs(self, argv):
112 if len(argv) > 1 and argv[1].lower() == 'discover':
113 self._do_discovery(argv[2:])
114 return
115
116 import getopt
Michael Foord5637f042010-04-02 21:42:47 +0000117 long_opts = ['help', 'verbose', 'quiet', 'failfast', 'catch', 'buffer']
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000118 try:
Michael Foord5637f042010-04-02 21:42:47 +0000119 options, args = getopt.getopt(argv[1:], 'hHvqfcb', long_opts)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000120 for opt, value in options:
121 if opt in ('-h','-H','--help'):
122 self.usageExit()
123 if opt in ('-q','--quiet'):
124 self.verbosity = 0
125 if opt in ('-v','--verbose'):
126 self.verbosity = 2
Michael Foord1b9e9532010-03-22 01:01:34 +0000127 if opt in ('-f','--failfast'):
Michael Foordfa2f1cd2010-03-26 03:18:31 +0000128 if self.failfast is None:
129 self.failfast = True
130 # Should this raise an exception if -f is not valid?
131 if opt in ('-c','--catch'):
132 if self.catchbreak is None:
133 self.catchbreak = True
134 # Should this raise an exception if -c is not valid?
Michael Foord5637f042010-04-02 21:42:47 +0000135 if opt in ('-b','--buffer'):
136 if self.buffer is None:
137 self.buffer = True
138 # Should this raise an exception if -b is not valid?
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000139 if len(args) == 0 and self.defaultTest is None:
Michael Foordd6aabcf2009-09-27 19:15:41 +0000140 # createTests will load tests from self.module
141 self.testNames = None
142 elif len(args) > 0:
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000143 self.testNames = args
144 if __name__ == '__main__':
145 # to support python -m unittest ...
146 self.module = None
147 else:
148 self.testNames = (self.defaultTest,)
149 self.createTests()
150 except getopt.error, msg:
151 self.usageExit(msg)
152
153 def createTests(self):
Michael Foordd6aabcf2009-09-27 19:15:41 +0000154 if self.testNames is None:
155 self.test = self.testLoader.loadTestsFromModule(self.module)
156 else:
157 self.test = self.testLoader.loadTestsFromNames(self.testNames,
158 self.module)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000159
Michael Foordcb66ee72013-02-10 23:59:46 +0000160 def _do_discovery(self, argv, Loader=None):
161 if Loader is None:
Michael Foordc36bf992013-02-11 12:53:21 +0000162 Loader = lambda: self.testLoader
Michael Foordcb66ee72013-02-10 23:59:46 +0000163
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000164 # handle command line args for test discovery
Michael Foord72b19772010-05-10 20:21:16 +0000165 self.progName = '%s discover' % self.progName
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000166 import optparse
167 parser = optparse.OptionParser()
Michael Foord72b19772010-05-10 20:21:16 +0000168 parser.prog = self.progName
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000169 parser.add_option('-v', '--verbose', dest='verbose', default=False,
170 help='Verbose output', action='store_true')
Michael Foordfa2f1cd2010-03-26 03:18:31 +0000171 if self.failfast != False:
172 parser.add_option('-f', '--failfast', dest='failfast', default=False,
173 help='Stop on first fail or error',
174 action='store_true')
175 if self.catchbreak != False:
176 parser.add_option('-c', '--catch', dest='catchbreak', default=False,
177 help='Catch ctrl-C and display results so far',
178 action='store_true')
Michael Foord5637f042010-04-02 21:42:47 +0000179 if self.buffer != False:
180 parser.add_option('-b', '--buffer', dest='buffer', default=False,
181 help='Buffer stdout and stderr during tests',
182 action='store_true')
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000183 parser.add_option('-s', '--start-directory', dest='start', default='.',
184 help="Directory to start discovery ('.' default)")
185 parser.add_option('-p', '--pattern', dest='pattern', default='test*.py',
186 help="Pattern to match tests ('test*.py' default)")
187 parser.add_option('-t', '--top-level-directory', dest='top', default=None,
188 help='Top level directory of project (defaults to start directory)')
189
190 options, args = parser.parse_args(argv)
191 if len(args) > 3:
192 self.usageExit()
193
194 for name, value in zip(('start', 'pattern', 'top'), args):
195 setattr(options, name, value)
196
Michael Foordfa2f1cd2010-03-26 03:18:31 +0000197 # only set options from the parsing here
198 # if they weren't set explicitly in the constructor
199 if self.failfast is None:
200 self.failfast = options.failfast
201 if self.catchbreak is None:
202 self.catchbreak = options.catchbreak
Michael Foord5637f042010-04-02 21:42:47 +0000203 if self.buffer is None:
204 self.buffer = options.buffer
Michael Foordfa2f1cd2010-03-26 03:18:31 +0000205
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000206 if options.verbose:
207 self.verbosity = 2
208
209 start_dir = options.start
210 pattern = options.pattern
211 top_level_dir = options.top
212
213 loader = Loader()
214 self.test = loader.discover(start_dir, pattern, top_level_dir)
215
216 def runTests(self):
Michael Foordfa2f1cd2010-03-26 03:18:31 +0000217 if self.catchbreak:
218 installHandler()
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000219 if self.testRunner is None:
220 self.testRunner = runner.TextTestRunner
221 if isinstance(self.testRunner, (type, types.ClassType)):
222 try:
Michael Foord1b9e9532010-03-22 01:01:34 +0000223 testRunner = self.testRunner(verbosity=self.verbosity,
Michael Foord5637f042010-04-02 21:42:47 +0000224 failfast=self.failfast,
225 buffer=self.buffer)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000226 except TypeError:
Michael Foord5637f042010-04-02 21:42:47 +0000227 # didn't accept the verbosity, buffer or failfast arguments
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000228 testRunner = self.testRunner()
229 else:
230 # it is assumed to be a TestRunner instance
231 testRunner = self.testRunner
232 self.result = testRunner.run(self.test)
233 if self.exit:
234 sys.exit(not self.result.wasSuccessful())
235
236main = TestProgram