blob: 63fbd160812696359e54502ff5a14fc59d203c0b [file] [log] [blame]
Benjamin Petersonbed7d042009-07-19 21:01:52 +00001"""Unittest main program"""
2
3import sys
4import os
5import types
6
7from . import loader, runner
8
Benjamin Petersondccc1fc2010-03-22 00:15:53 +00009__unittest = True
10
Benjamin Petersonbed7d042009-07-19 21:01:52 +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
Benjamin Peterson8769fd82010-03-22 01:13:48 +000019 -f, --failfast Stop on first failure
Benjamin Petersonbed7d042009-07-19 21:01:52 +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
Benjamin Peterson8769fd82010-03-22 01:13:48 +000034 -f, --failfast Stop on first failure
Benjamin Petersonbed7d042009-07-19 21:01:52 +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
Benjamin Peterson8769fd82010-03-22 01:13:48 +000051 -f, --failfast Stop on first failure
Benjamin Petersonbed7d042009-07-19 21:01:52 +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,
Benjamin Peterson8769fd82010-03-22 01:13:48 +000075 verbosity=1, failfast=False):
Benjamin Petersonbed7d042009-07-19 21:01:52 +000076 if isinstance(module, str):
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
Benjamin Peterson8769fd82010-03-22 01:13:48 +000086 self.failfast = failfast
Benjamin Petersonbed7d042009-07-19 21:01:52 +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
Benjamin Peterson8769fd82010-03-22 01:13:48 +0000107 long_opts = ['help', 'verbose', 'quiet', 'failfast']
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000108 try:
Benjamin Peterson8769fd82010-03-22 01:13:48 +0000109 options, args = getopt.getopt(argv[1:], 'hHvqf', long_opts)
Benjamin Petersonbed7d042009-07-19 21:01:52 +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
Benjamin Peterson8769fd82010-03-22 01:13:48 +0000117 if opt in ('-f','--failfast'):
118 self.failfast = True
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000119 if len(args) == 0 and self.defaultTest is None:
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +0000120 # createTests will load tests from self.module
121 self.testNames = None
122 elif len(args) > 0:
Benjamin Petersonbed7d042009-07-19 21:01:52 +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 as msg:
131 self.usageExit(msg)
132
133 def createTests(self):
Benjamin Peterson4ac9ce42009-10-04 14:49: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 Petersonbed7d042009-07-19 21:01:52 +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')
Benjamin Peterson8769fd82010-03-22 01:13:48 +0000146 parser.add_option('-f', '--failfast', dest='failfast', default=False,
147 help='Stop on first fail or error', action='store_true')
Benjamin Petersonbed7d042009-07-19 21:01:52 +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
Benjamin Peterson8769fd82010-03-22 01:13:48 +0000164 if options.failfast:
165 self.failfast = True
Benjamin Petersonbed7d042009-07-19 21:01:52 +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):
178 try:
Benjamin Peterson8769fd82010-03-22 01:13:48 +0000179 testRunner = self.testRunner(verbosity=self.verbosity,
180 failfast=self.failfast)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000181 except TypeError:
Benjamin Peterson8769fd82010-03-22 01:13:48 +0000182 # didn't accept the verbosity or failfast argument
Benjamin Petersonbed7d042009-07-19 21:01:52 +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