blob: 74d875cb1d4c769aa068740ec09c1956a60e58ab [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:
25 %(progName)s test_module - run tests from test_module
26 %(progName)s test_module.TestClass - run tests from
27 test_module.TestClass
28 %(progName)s test_module.TestClass.test_method - run specified test method
29
30[tests] can be a list of any number of test modules, classes and test
31methods.
32
33Alternative Usage: %(progName)s discover [options]
34
35Options:
36 -v, --verbose Verbose output
Michael Foordd43b63f2010-04-03 14:52:18 +000037%(failfast)s%(catchbreak)s%(buffer)s -s directory Directory to start discovery ('.' default)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000038 -p pattern Pattern to match test files ('test*.py' default)
39 -t directory Top level directory of project (default to
40 start directory)
41
42For test discovery all test modules must be importable from the top
43level directory of the project.
44"""
45
46USAGE_FROM_MODULE = """\
47Usage: %(progName)s [options] [test] [...]
48
49Options:
50 -h, --help Show this message
51 -v, --verbose Verbose output
52 -q, --quiet Minimal output
Michael Foordd43b63f2010-04-03 14:52:18 +000053%(failfast)s%(catchbreak)s%(buffer)s
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000054Examples:
55 %(progName)s - run default set of tests
56 %(progName)s MyTestSuite - run suite 'MyTestSuite'
57 %(progName)s MyTestCase.testSomething - run MyTestCase.testSomething
58 %(progName)s MyTestCase - run all 'test*' test methods
59 in MyTestCase
60"""
61
Michael Foordfa2f1cd2010-03-26 03:18:31 +000062
63
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000064class TestProgram(object):
65 """A command-line program that runs a set of tests; this is primarily
66 for making test modules conveniently executable.
67 """
Michael Foordeef159b2010-03-22 02:49:08 +000068 USAGE = USAGE_FROM_MODULE
Michael Foordfa2f1cd2010-03-26 03:18:31 +000069
70 # defaults for testing
Michael Foord5637f042010-04-02 21:42:47 +000071 failfast = catchbreak = buffer = None
Michael Foordfa2f1cd2010-03-26 03:18:31 +000072
Michael Foord215d3942010-05-07 15:34:08 +000073 def __init__(self, module='__main__', defaultTest=None, argv=None,
74 testRunner=None, testLoader=loader.defaultTestLoader,
75 exit=True, verbosity=1, failfast=None, catchbreak=None,
76 buffer=None):
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000077 if isinstance(module, basestring):
78 self.module = __import__(module)
79 for part in module.split('.')[1:]:
80 self.module = getattr(self.module, part)
81 else:
82 self.module = module
83 if argv is None:
84 argv = sys.argv
85
86 self.exit = exit
Michael Foord1b9e9532010-03-22 01:01:34 +000087 self.failfast = failfast
Michael Foordfa2f1cd2010-03-26 03:18:31 +000088 self.catchbreak = catchbreak
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000089 self.verbosity = verbosity
Michael Foord5637f042010-04-02 21:42:47 +000090 self.buffer = buffer
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000091 self.defaultTest = defaultTest
92 self.testRunner = testRunner
93 self.testLoader = testLoader
94 self.progName = os.path.basename(argv[0])
95 self.parseArgs(argv)
96 self.runTests()
97
98 def usageExit(self, msg=None):
99 if msg:
100 print msg
Michael Foord3dd9f402010-04-03 15:20:00 +0000101 usage = {'progName': self.progName, 'catchbreak': '', 'failfast': '',
102 'buffer': ''}
Michael Foordfa2f1cd2010-03-26 03:18:31 +0000103 if self.failfast != False:
104 usage['failfast'] = FAILFAST
105 if self.catchbreak != False:
106 usage['catchbreak'] = CATCHBREAK
Michael Foordd43b63f2010-04-03 14:52:18 +0000107 if self.buffer != False:
108 usage['buffer'] = BUFFEROUTPUT
Michael Foordfa2f1cd2010-03-26 03:18:31 +0000109 print self.USAGE % usage
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000110 sys.exit(2)
111
112 def parseArgs(self, argv):
113 if len(argv) > 1 and argv[1].lower() == 'discover':
114 self._do_discovery(argv[2:])
115 return
116
117 import getopt
Michael Foord5637f042010-04-02 21:42:47 +0000118 long_opts = ['help', 'verbose', 'quiet', 'failfast', 'catch', 'buffer']
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000119 try:
Michael Foord5637f042010-04-02 21:42:47 +0000120 options, args = getopt.getopt(argv[1:], 'hHvqfcb', long_opts)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +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
Michael Foord1b9e9532010-03-22 01:01:34 +0000128 if opt in ('-f','--failfast'):
Michael Foordfa2f1cd2010-03-26 03:18:31 +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?
Michael Foord5637f042010-04-02 21:42:47 +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 Petersond7b0eeb2009-07-19 20:18:21 +0000140 if len(args) == 0 and self.defaultTest is None:
Michael Foordd6aabcf2009-09-27 19:15:41 +0000141 # createTests will load tests from self.module
142 self.testNames = None
143 elif len(args) > 0:
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +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, msg:
152 self.usageExit(msg)
153
154 def createTests(self):
Michael Foordd6aabcf2009-09-27 19:15: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 Petersond7b0eeb2009-07-19 20:18:21 +0000160
161 def _do_discovery(self, argv, Loader=loader.TestLoader):
162 # handle command line args for test discovery
163 import optparse
164 parser = optparse.OptionParser()
165 parser.add_option('-v', '--verbose', dest='verbose', default=False,
166 help='Verbose output', action='store_true')
Michael Foordfa2f1cd2010-03-26 03:18:31 +0000167 if self.failfast != False:
168 parser.add_option('-f', '--failfast', dest='failfast', default=False,
169 help='Stop on first fail or error',
170 action='store_true')
171 if self.catchbreak != False:
172 parser.add_option('-c', '--catch', dest='catchbreak', default=False,
173 help='Catch ctrl-C and display results so far',
174 action='store_true')
Michael Foord5637f042010-04-02 21:42:47 +0000175 if self.buffer != False:
176 parser.add_option('-b', '--buffer', dest='buffer', default=False,
177 help='Buffer stdout and stderr during tests',
178 action='store_true')
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000179 parser.add_option('-s', '--start-directory', dest='start', default='.',
180 help="Directory to start discovery ('.' default)")
181 parser.add_option('-p', '--pattern', dest='pattern', default='test*.py',
182 help="Pattern to match tests ('test*.py' default)")
183 parser.add_option('-t', '--top-level-directory', dest='top', default=None,
184 help='Top level directory of project (defaults to start directory)')
185
186 options, args = parser.parse_args(argv)
187 if len(args) > 3:
188 self.usageExit()
189
190 for name, value in zip(('start', 'pattern', 'top'), args):
191 setattr(options, name, value)
192
Michael Foordfa2f1cd2010-03-26 03:18:31 +0000193 # only set options from the parsing here
194 # if they weren't set explicitly in the constructor
195 if self.failfast is None:
196 self.failfast = options.failfast
197 if self.catchbreak is None:
198 self.catchbreak = options.catchbreak
Michael Foord5637f042010-04-02 21:42:47 +0000199 if self.buffer is None:
200 self.buffer = options.buffer
Michael Foordfa2f1cd2010-03-26 03:18:31 +0000201
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000202 if options.verbose:
203 self.verbosity = 2
204
205 start_dir = options.start
206 pattern = options.pattern
207 top_level_dir = options.top
208
209 loader = Loader()
210 self.test = loader.discover(start_dir, pattern, top_level_dir)
211
212 def runTests(self):
Michael Foordfa2f1cd2010-03-26 03:18:31 +0000213 if self.catchbreak:
214 installHandler()
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000215 if self.testRunner is None:
216 self.testRunner = runner.TextTestRunner
217 if isinstance(self.testRunner, (type, types.ClassType)):
218 try:
Michael Foord1b9e9532010-03-22 01:01:34 +0000219 testRunner = self.testRunner(verbosity=self.verbosity,
Michael Foord5637f042010-04-02 21:42:47 +0000220 failfast=self.failfast,
221 buffer=self.buffer)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000222 except TypeError:
Michael Foord5637f042010-04-02 21:42:47 +0000223 # didn't accept the verbosity, buffer or failfast arguments
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000224 testRunner = self.testRunner()
225 else:
226 # it is assumed to be a TestRunner instance
227 testRunner = self.testRunner
228 self.result = testRunner.run(self.test)
229 if self.exit:
230 sys.exit(not self.result.wasSuccessful())
231
232main = TestProgram