blob: b53af05cac5fb098f27fae1778bb9efcb1ddbd4b [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
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000073 def __init__(self, module='__main__', defaultTest=None,
74 argv=None, testRunner=None,
75 testLoader=loader.defaultTestLoader, exit=True,
Michael Foord5637f042010-04-02 21:42:47 +000076 verbosity=1, failfast=None, catchbreak=None, 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 Foordfa2f1cd2010-03-26 03:18:31 +0000101 usage = {'progName': self.progName, 'catchbreak': '', 'failfast': ''}
102 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
160 def _do_discovery(self, argv, Loader=loader.TestLoader):
161 # handle command line args for test discovery
162 import optparse
163 parser = optparse.OptionParser()
164 parser.add_option('-v', '--verbose', dest='verbose', default=False,
165 help='Verbose output', action='store_true')
Michael Foordfa2f1cd2010-03-26 03:18:31 +0000166 if self.failfast != False:
167 parser.add_option('-f', '--failfast', dest='failfast', default=False,
168 help='Stop on first fail or error',
169 action='store_true')
170 if self.catchbreak != False:
171 parser.add_option('-c', '--catch', dest='catchbreak', default=False,
172 help='Catch ctrl-C and display results so far',
173 action='store_true')
Michael Foord5637f042010-04-02 21:42:47 +0000174 if self.buffer != False:
175 parser.add_option('-b', '--buffer', dest='buffer', default=False,
176 help='Buffer stdout and stderr during tests',
177 action='store_true')
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000178 parser.add_option('-s', '--start-directory', dest='start', default='.',
179 help="Directory to start discovery ('.' default)")
180 parser.add_option('-p', '--pattern', dest='pattern', default='test*.py',
181 help="Pattern to match tests ('test*.py' default)")
182 parser.add_option('-t', '--top-level-directory', dest='top', default=None,
183 help='Top level directory of project (defaults to start directory)')
184
185 options, args = parser.parse_args(argv)
186 if len(args) > 3:
187 self.usageExit()
188
189 for name, value in zip(('start', 'pattern', 'top'), args):
190 setattr(options, name, value)
191
Michael Foordfa2f1cd2010-03-26 03:18:31 +0000192 # only set options from the parsing here
193 # if they weren't set explicitly in the constructor
194 if self.failfast is None:
195 self.failfast = options.failfast
196 if self.catchbreak is None:
197 self.catchbreak = options.catchbreak
Michael Foord5637f042010-04-02 21:42:47 +0000198 if self.buffer is None:
199 self.buffer = options.buffer
Michael Foordfa2f1cd2010-03-26 03:18:31 +0000200
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000201 if options.verbose:
202 self.verbosity = 2
203
204 start_dir = options.start
205 pattern = options.pattern
206 top_level_dir = options.top
207
208 loader = Loader()
209 self.test = loader.discover(start_dir, pattern, top_level_dir)
210
211 def runTests(self):
Michael Foordfa2f1cd2010-03-26 03:18:31 +0000212 if self.catchbreak:
213 installHandler()
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000214 if self.testRunner is None:
215 self.testRunner = runner.TextTestRunner
216 if isinstance(self.testRunner, (type, types.ClassType)):
217 try:
Michael Foord1b9e9532010-03-22 01:01:34 +0000218 testRunner = self.testRunner(verbosity=self.verbosity,
Michael Foord5637f042010-04-02 21:42:47 +0000219 failfast=self.failfast,
220 buffer=self.buffer)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000221 except TypeError:
Michael Foord5637f042010-04-02 21:42:47 +0000222 # didn't accept the verbosity, buffer or failfast arguments
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000223 testRunner = self.testRunner()
224 else:
225 # it is assumed to be a TestRunner instance
226 testRunner = self.testRunner
227 self.result = testRunner.run(self.test)
228 if self.exit:
229 sys.exit(not self.result.wasSuccessful())
230
231main = TestProgram