blob: 0154017a924f0ffd70a9e5e0afe7901250f40d1d [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
Benjamin Petersonbed7d042009-07-19 21:01:52 +000061class TestProgram(object):
62 """A command-line program that runs a set of tests; this is primarily
63 for making test modules conveniently executable.
64 """
Benjamin Petersoneab4b4c2010-03-22 02:53:52 +000065 USAGE = USAGE_FROM_MODULE
Benjamin Petersonbed7d042009-07-19 21:01:52 +000066 def __init__(self, module='__main__', defaultTest=None,
67 argv=None, testRunner=None,
68 testLoader=loader.defaultTestLoader, exit=True,
Benjamin Peterson8769fd82010-03-22 01:13:48 +000069 verbosity=1, failfast=False):
Benjamin Petersonbed7d042009-07-19 21:01:52 +000070 if isinstance(module, str):
71 self.module = __import__(module)
72 for part in module.split('.')[1:]:
73 self.module = getattr(self.module, part)
74 else:
75 self.module = module
76 if argv is None:
77 argv = sys.argv
78
79 self.exit = exit
Benjamin Peterson8769fd82010-03-22 01:13:48 +000080 self.failfast = failfast
Benjamin Petersonbed7d042009-07-19 21:01:52 +000081 self.verbosity = verbosity
82 self.defaultTest = defaultTest
83 self.testRunner = testRunner
84 self.testLoader = testLoader
85 self.progName = os.path.basename(argv[0])
86 self.parseArgs(argv)
87 self.runTests()
88
89 def usageExit(self, msg=None):
90 if msg:
91 print(msg)
92 print(self.USAGE % self.__dict__)
93 sys.exit(2)
94
95 def parseArgs(self, argv):
96 if len(argv) > 1 and argv[1].lower() == 'discover':
97 self._do_discovery(argv[2:])
98 return
99
100 import getopt
Benjamin Peterson8769fd82010-03-22 01:13:48 +0000101 long_opts = ['help', 'verbose', 'quiet', 'failfast']
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000102 try:
Benjamin Peterson8769fd82010-03-22 01:13:48 +0000103 options, args = getopt.getopt(argv[1:], 'hHvqf', long_opts)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000104 for opt, value in options:
105 if opt in ('-h','-H','--help'):
106 self.usageExit()
107 if opt in ('-q','--quiet'):
108 self.verbosity = 0
109 if opt in ('-v','--verbose'):
110 self.verbosity = 2
Benjamin Peterson8769fd82010-03-22 01:13:48 +0000111 if opt in ('-f','--failfast'):
112 self.failfast = True
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000113 if len(args) == 0 and self.defaultTest is None:
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +0000114 # createTests will load tests from self.module
115 self.testNames = None
116 elif len(args) > 0:
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000117 self.testNames = args
118 if __name__ == '__main__':
119 # to support python -m unittest ...
120 self.module = None
121 else:
122 self.testNames = (self.defaultTest,)
123 self.createTests()
124 except getopt.error as msg:
125 self.usageExit(msg)
126
127 def createTests(self):
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +0000128 if self.testNames is None:
129 self.test = self.testLoader.loadTestsFromModule(self.module)
130 else:
131 self.test = self.testLoader.loadTestsFromNames(self.testNames,
132 self.module)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000133
134 def _do_discovery(self, argv, Loader=loader.TestLoader):
135 # handle command line args for test discovery
136 import optparse
137 parser = optparse.OptionParser()
138 parser.add_option('-v', '--verbose', dest='verbose', default=False,
139 help='Verbose output', action='store_true')
Benjamin Peterson8769fd82010-03-22 01:13:48 +0000140 parser.add_option('-f', '--failfast', dest='failfast', default=False,
141 help='Stop on first fail or error', action='store_true')
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000142 parser.add_option('-s', '--start-directory', dest='start', default='.',
143 help="Directory to start discovery ('.' default)")
144 parser.add_option('-p', '--pattern', dest='pattern', default='test*.py',
145 help="Pattern to match tests ('test*.py' default)")
146 parser.add_option('-t', '--top-level-directory', dest='top', default=None,
147 help='Top level directory of project (defaults to start directory)')
148
149 options, args = parser.parse_args(argv)
150 if len(args) > 3:
151 self.usageExit()
152
153 for name, value in zip(('start', 'pattern', 'top'), args):
154 setattr(options, name, value)
155
Benjamin Peterson434ae772010-03-22 01:46:47 +0000156 self.failfast = options.failfast
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000157 if options.verbose:
158 self.verbosity = 2
159
160 start_dir = options.start
161 pattern = options.pattern
162 top_level_dir = options.top
163
164 loader = Loader()
165 self.test = loader.discover(start_dir, pattern, top_level_dir)
166
167 def runTests(self):
168 if self.testRunner is None:
169 self.testRunner = runner.TextTestRunner
170 if isinstance(self.testRunner, type):
171 try:
Benjamin Peterson8769fd82010-03-22 01:13:48 +0000172 testRunner = self.testRunner(verbosity=self.verbosity,
173 failfast=self.failfast)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000174 except TypeError:
Benjamin Petersonf8197c32010-03-22 02:02:37 +0000175 # didn't accept the verbosity or failfast arguments
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000176 testRunner = self.testRunner()
177 else:
178 # it is assumed to be a TestRunner instance
179 testRunner = self.testRunner
180 self.result = testRunner.run(self.test)
181 if self.exit:
182 sys.exit(not self.result.wasSuccessful())
183
184main = TestProgram