blob: e2703ce727072d34e584804c98510feca27540df [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
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000012
Michael Foordfa2f1cd2010-03-26 03:18:31 +000013FAILFAST = " -f, --failfast Stop on first failure\n"
14CATCHBREAK = " -c, --catch Catch control-C and display results\n"
15
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 Foordfa2f1cd2010-03-26 03:18:31 +000023%(failfast)s%(catchbreak)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 Foordfa2f1cd2010-03-26 03:18:31 +000037%(failfast)s%(catchbreak)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 Foordfa2f1cd2010-03-26 03:18:31 +000053%(failfast)s%(catchbreak)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
71 failfast = catchbreak = None
72
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 Foordfa2f1cd2010-03-26 03:18:31 +000076 verbosity=1, failfast=None, catchbreak=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
90 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 Foordfa2f1cd2010-03-26 03:18:31 +0000100 usage = {'progName': self.progName, 'catchbreak': '', 'failfast': ''}
101 if self.failfast != False:
102 usage['failfast'] = FAILFAST
103 if self.catchbreak != False:
104 usage['catchbreak'] = CATCHBREAK
105 print self.USAGE % usage
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000106 sys.exit(2)
107
108 def parseArgs(self, argv):
109 if len(argv) > 1 and argv[1].lower() == 'discover':
110 self._do_discovery(argv[2:])
111 return
112
113 import getopt
Michael Foordfa2f1cd2010-03-26 03:18:31 +0000114 long_opts = ['help', 'verbose', 'quiet', 'failfast', 'catch']
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000115 try:
Michael Foordfa2f1cd2010-03-26 03:18:31 +0000116 options, args = getopt.getopt(argv[1:], 'hHvqfc', long_opts)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000117 for opt, value in options:
118 if opt in ('-h','-H','--help'):
119 self.usageExit()
120 if opt in ('-q','--quiet'):
121 self.verbosity = 0
122 if opt in ('-v','--verbose'):
123 self.verbosity = 2
Michael Foord1b9e9532010-03-22 01:01:34 +0000124 if opt in ('-f','--failfast'):
Michael Foordfa2f1cd2010-03-26 03:18:31 +0000125 if self.failfast is None:
126 self.failfast = True
127 # Should this raise an exception if -f is not valid?
128 if opt in ('-c','--catch'):
129 if self.catchbreak is None:
130 self.catchbreak = True
131 # Should this raise an exception if -c is not valid?
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000132 if len(args) == 0 and self.defaultTest is None:
Michael Foordd6aabcf2009-09-27 19:15:41 +0000133 # createTests will load tests from self.module
134 self.testNames = None
135 elif len(args) > 0:
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000136 self.testNames = args
137 if __name__ == '__main__':
138 # to support python -m unittest ...
139 self.module = None
140 else:
141 self.testNames = (self.defaultTest,)
142 self.createTests()
143 except getopt.error, msg:
144 self.usageExit(msg)
145
146 def createTests(self):
Michael Foordd6aabcf2009-09-27 19:15:41 +0000147 if self.testNames is None:
148 self.test = self.testLoader.loadTestsFromModule(self.module)
149 else:
150 self.test = self.testLoader.loadTestsFromNames(self.testNames,
151 self.module)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000152
153 def _do_discovery(self, argv, Loader=loader.TestLoader):
154 # handle command line args for test discovery
155 import optparse
156 parser = optparse.OptionParser()
157 parser.add_option('-v', '--verbose', dest='verbose', default=False,
158 help='Verbose output', action='store_true')
Michael Foordfa2f1cd2010-03-26 03:18:31 +0000159 if self.failfast != False:
160 parser.add_option('-f', '--failfast', dest='failfast', default=False,
161 help='Stop on first fail or error',
162 action='store_true')
163 if self.catchbreak != False:
164 parser.add_option('-c', '--catch', dest='catchbreak', default=False,
165 help='Catch ctrl-C and display results so far',
166 action='store_true')
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000167 parser.add_option('-s', '--start-directory', dest='start', default='.',
168 help="Directory to start discovery ('.' default)")
169 parser.add_option('-p', '--pattern', dest='pattern', default='test*.py',
170 help="Pattern to match tests ('test*.py' default)")
171 parser.add_option('-t', '--top-level-directory', dest='top', default=None,
172 help='Top level directory of project (defaults to start directory)')
173
174 options, args = parser.parse_args(argv)
175 if len(args) > 3:
176 self.usageExit()
177
178 for name, value in zip(('start', 'pattern', 'top'), args):
179 setattr(options, name, value)
180
Michael Foordfa2f1cd2010-03-26 03:18:31 +0000181 # only set options from the parsing here
182 # if they weren't set explicitly in the constructor
183 if self.failfast is None:
184 self.failfast = options.failfast
185 if self.catchbreak is None:
186 self.catchbreak = options.catchbreak
187
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000188 if options.verbose:
189 self.verbosity = 2
190
191 start_dir = options.start
192 pattern = options.pattern
193 top_level_dir = options.top
194
195 loader = Loader()
196 self.test = loader.discover(start_dir, pattern, top_level_dir)
197
198 def runTests(self):
Michael Foordfa2f1cd2010-03-26 03:18:31 +0000199 if self.catchbreak:
200 installHandler()
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000201 if self.testRunner is None:
202 self.testRunner = runner.TextTestRunner
203 if isinstance(self.testRunner, (type, types.ClassType)):
204 try:
Michael Foord1b9e9532010-03-22 01:01:34 +0000205 testRunner = self.testRunner(verbosity=self.verbosity,
206 failfast=self.failfast)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000207 except TypeError:
Michael Foord0ce16722010-03-22 01:56:54 +0000208 # didn't accept the verbosity or failfast arguments
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000209 testRunner = self.testRunner()
210 else:
211 # it is assumed to be a TestRunner instance
212 testRunner = self.testRunner
213 self.result = testRunner.run(self.test)
214 if self.exit:
215 sys.exit(not self.result.wasSuccessful())
216
217main = TestProgram