blob: f5b516cbb972acf898abb7099fc0da99f0123253 [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
8
Michael Foordb1aa30f2010-03-22 00:06:30 +00009__unittest = True
10
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000011
12USAGE_AS_MAIN = """\
13Usage: %(progName)s [options] [tests]
14
15Options:
16 -h, --help Show this message
17 -v, --verbose Verbose output
18 -q, --quiet Minimal output
Michael Foord1b9e9532010-03-22 01:01:34 +000019 -f, --failfast Stop on first failure
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000020
21Examples:
22 %(progName)s test_module - run tests from test_module
23 %(progName)s test_module.TestClass - run tests from
24 test_module.TestClass
25 %(progName)s test_module.TestClass.test_method - run specified test method
26
27[tests] can be a list of any number of test modules, classes and test
28methods.
29
30Alternative Usage: %(progName)s discover [options]
31
32Options:
33 -v, --verbose Verbose output
Michael Foord1b9e9532010-03-22 01:01:34 +000034 -f, --failfast Stop on first failure
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000035 -s directory Directory to start discovery ('.' default)
36 -p pattern Pattern to match test files ('test*.py' default)
37 -t directory Top level directory of project (default to
38 start directory)
39
40For test discovery all test modules must be importable from the top
41level directory of the project.
42"""
43
44USAGE_FROM_MODULE = """\
45Usage: %(progName)s [options] [test] [...]
46
47Options:
48 -h, --help Show this message
49 -v, --verbose Verbose output
50 -q, --quiet Minimal output
Michael Foord1b9e9532010-03-22 01:01:34 +000051 -f, --failfast Stop on first failure
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000052
53Examples:
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
61if __name__ == '__main__':
62 USAGE = USAGE_AS_MAIN
63else:
64 USAGE = USAGE_FROM_MODULE
65
66
67class TestProgram(object):
68 """A command-line program that runs a set of tests; this is primarily
69 for making test modules conveniently executable.
70 """
71 USAGE = USAGE
72 def __init__(self, module='__main__', defaultTest=None,
73 argv=None, testRunner=None,
74 testLoader=loader.defaultTestLoader, exit=True,
Michael Foord1b9e9532010-03-22 01:01:34 +000075 verbosity=1, failfast=False):
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
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000087 self.verbosity = verbosity
88 self.defaultTest = defaultTest
89 self.testRunner = testRunner
90 self.testLoader = testLoader
91 self.progName = os.path.basename(argv[0])
92 self.parseArgs(argv)
93 self.runTests()
94
95 def usageExit(self, msg=None):
96 if msg:
97 print msg
98 print self.USAGE % self.__dict__
99 sys.exit(2)
100
101 def parseArgs(self, argv):
102 if len(argv) > 1 and argv[1].lower() == 'discover':
103 self._do_discovery(argv[2:])
104 return
105
106 import getopt
Michael Foord1b9e9532010-03-22 01:01:34 +0000107 long_opts = ['help', 'verbose', 'quiet', 'failfast']
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000108 try:
Michael Foord1b9e9532010-03-22 01:01:34 +0000109 options, args = getopt.getopt(argv[1:], 'hHvqf', long_opts)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000110 for opt, value in options:
111 if opt in ('-h','-H','--help'):
112 self.usageExit()
113 if opt in ('-q','--quiet'):
114 self.verbosity = 0
115 if opt in ('-v','--verbose'):
116 self.verbosity = 2
Michael Foord1b9e9532010-03-22 01:01:34 +0000117 if opt in ('-f','--failfast'):
118 self.failfast = True
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000119 if len(args) == 0 and self.defaultTest is None:
Michael Foordd6aabcf2009-09-27 19:15:41 +0000120 # createTests will load tests from self.module
121 self.testNames = None
122 elif len(args) > 0:
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000123 self.testNames = args
124 if __name__ == '__main__':
125 # to support python -m unittest ...
126 self.module = None
127 else:
128 self.testNames = (self.defaultTest,)
129 self.createTests()
130 except getopt.error, msg:
131 self.usageExit(msg)
132
133 def createTests(self):
Michael Foordd6aabcf2009-09-27 19:15:41 +0000134 if self.testNames is None:
135 self.test = self.testLoader.loadTestsFromModule(self.module)
136 else:
137 self.test = self.testLoader.loadTestsFromNames(self.testNames,
138 self.module)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000139
140 def _do_discovery(self, argv, Loader=loader.TestLoader):
141 # handle command line args for test discovery
142 import optparse
143 parser = optparse.OptionParser()
144 parser.add_option('-v', '--verbose', dest='verbose', default=False,
145 help='Verbose output', action='store_true')
Michael Foord1b9e9532010-03-22 01:01:34 +0000146 parser.add_option('-f', '--failfast', dest='failfast', default=False,
147 help='Stop on first fail or error', action='store_true')
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000148 parser.add_option('-s', '--start-directory', dest='start', default='.',
149 help="Directory to start discovery ('.' default)")
150 parser.add_option('-p', '--pattern', dest='pattern', default='test*.py',
151 help="Pattern to match tests ('test*.py' default)")
152 parser.add_option('-t', '--top-level-directory', dest='top', default=None,
153 help='Top level directory of project (defaults to start directory)')
154
155 options, args = parser.parse_args(argv)
156 if len(args) > 3:
157 self.usageExit()
158
159 for name, value in zip(('start', 'pattern', 'top'), args):
160 setattr(options, name, value)
161
162 if options.verbose:
163 self.verbosity = 2
Michael Foord1b9e9532010-03-22 01:01:34 +0000164 if options.failfast:
165 self.failfast = True
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000166
167 start_dir = options.start
168 pattern = options.pattern
169 top_level_dir = options.top
170
171 loader = Loader()
172 self.test = loader.discover(start_dir, pattern, top_level_dir)
173
174 def runTests(self):
175 if self.testRunner is None:
176 self.testRunner = runner.TextTestRunner
177 if isinstance(self.testRunner, (type, types.ClassType)):
178 try:
Michael Foord1b9e9532010-03-22 01:01:34 +0000179 testRunner = self.testRunner(verbosity=self.verbosity,
180 failfast=self.failfast)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000181 except TypeError:
Michael Foord1b9e9532010-03-22 01:01:34 +0000182 # didn't accept the verbosity or failfast argument
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000183 testRunner = self.testRunner()
184 else:
185 # it is assumed to be a TestRunner instance
186 testRunner = self.testRunner
187 self.result = testRunner.run(self.test)
188 if self.exit:
189 sys.exit(not self.result.wasSuccessful())
190
191main = TestProgram