Home | History | Annotate | Download | only in unittest2
      1 """Unittest main program"""
      2 
      3 import sys
      4 import os
      5 import types
      6 
      7 from unittest2 import loader, runner
      8 try:
      9     from unittest2.signals import installHandler
     10 except ImportError:
     11     installHandler = None
     12 
     13 __unittest = True
     14 
     15 FAILFAST     = "  -f, --failfast   Stop on first failure\n"
     16 CATCHBREAK   = "  -c, --catch      Catch control-C and display results\n"
     17 BUFFEROUTPUT = "  -b, --buffer     Buffer stdout and stderr during test runs\n"
     18 
     19 USAGE_AS_MAIN = """\
     20 Usage: %(progName)s [options] [tests]
     21 
     22 Options:
     23   -h, --help       Show this message
     24   -v, --verbose    Verbose output
     25   -q, --quiet      Minimal output
     26 %(failfast)s%(catchbreak)s%(buffer)s
     27 Examples:
     28   %(progName)s test_module                       - run tests from test_module
     29   %(progName)s test_module.TestClass             - run tests from
     30                                                    test_module.TestClass
     31   %(progName)s test_module.TestClass.test_method - run specified test method
     32 
     33 [tests] can be a list of any number of test modules, classes and test
     34 methods.
     35 
     36 Alternative Usage: %(progName)s discover [options]
     37 
     38 Options:
     39   -v, --verbose    Verbose output
     40 %(failfast)s%(catchbreak)s%(buffer)s  -s directory     Directory to start discovery ('.' default)
     41   -p pattern       Pattern to match test files ('test*.py' default)
     42   -t directory     Top level directory of project (default to
     43                    start directory)
     44 
     45 For test discovery all test modules must be importable from the top
     46 level directory of the project.
     47 """
     48 
     49 USAGE_FROM_MODULE = """\
     50 Usage: %(progName)s [options] [test] [...]
     51 
     52 Options:
     53   -h, --help       Show this message
     54   -v, --verbose    Verbose output
     55   -q, --quiet      Minimal output
     56 %(failfast)s%(catchbreak)s%(buffer)s
     57 Examples:
     58   %(progName)s                               - run default set of tests
     59   %(progName)s MyTestSuite                   - run suite 'MyTestSuite'
     60   %(progName)s MyTestCase.testSomething      - run MyTestCase.testSomething
     61   %(progName)s MyTestCase                    - run all 'test*' test methods
     62                                                in MyTestCase
     63 """
     64 
     65 
     66 class TestProgram(object):
     67     """A command-line program that runs a set of tests; this is primarily
     68        for making test modules conveniently executable.
     69     """
     70     USAGE = USAGE_FROM_MODULE
     71 
     72     # defaults for testing
     73     failfast = catchbreak = buffer = progName = None
     74 
     75     def __init__(self, module='__main__', defaultTest=None,
     76                  argv=None, testRunner=None,
     77                  testLoader=loader.defaultTestLoader, exit=True,
     78                  verbosity=1, failfast=None, catchbreak=None, buffer=None):
     79         if isinstance(module, basestring):
     80             self.module = __import__(module)
     81             for part in module.split('.')[1:]:
     82                 self.module = getattr(self.module, part)
     83         else:
     84             self.module = module
     85         if argv is None:
     86             argv = sys.argv
     87 
     88         self.exit = exit
     89         self.verbosity = verbosity
     90         self.failfast = failfast
     91         self.catchbreak = catchbreak
     92         self.buffer = buffer
     93         self.defaultTest = defaultTest
     94         self.testRunner = testRunner
     95         self.testLoader = testLoader
     96         self.progName = os.path.basename(argv[0])
     97         self.parseArgs(argv)
     98         self.runTests()
     99 
    100     def usageExit(self, msg=None):
    101         if msg:
    102             print msg
    103         usage = {'progName': self.progName, 'catchbreak': '', 'failfast': '',
    104                  'buffer': ''}
    105         if self.failfast != False:
    106             usage['failfast'] = FAILFAST
    107         if self.catchbreak != False and installHandler is not None:
    108             usage['catchbreak'] = CATCHBREAK
    109         if self.buffer != False:
    110             usage['buffer'] = BUFFEROUTPUT
    111         print self.USAGE % usage
    112         sys.exit(2)
    113 
    114     def parseArgs(self, argv):
    115         if len(argv) > 1 and argv[1].lower() == 'discover':
    116             self._do_discovery(argv[2:])
    117             return
    118 
    119         import getopt
    120         long_opts = ['help', 'verbose', 'quiet', 'failfast', 'catch', 'buffer']
    121         try:
    122             options, args = getopt.getopt(argv[1:], 'hHvqfcb', long_opts)
    123             for opt, value in options:
    124                 if opt in ('-h','-H','--help'):
    125                     self.usageExit()
    126                 if opt in ('-q','--quiet'):
    127                     self.verbosity = 0
    128                 if opt in ('-v','--verbose'):
    129                     self.verbosity = 2
    130                 if opt in ('-f','--failfast'):
    131                     if self.failfast is None:
    132                         self.failfast = True
    133                     # Should this raise an exception if -f is not valid?
    134                 if opt in ('-c','--catch'):
    135                     if self.catchbreak is None and installHandler is not None:
    136                         self.catchbreak = True
    137                     # Should this raise an exception if -c is not valid?
    138                 if opt in ('-b','--buffer'):
    139                     if self.buffer is None:
    140                         self.buffer = True
    141                     # Should this raise an exception if -b is not valid?
    142             if len(args) == 0 and self.defaultTest is None:
    143                 # createTests will load tests from self.module
    144                 self.testNames = None
    145             elif len(args) > 0:
    146                 self.testNames = args
    147                 if __name__ == '__main__':
    148                     # to support python -m unittest ...
    149                     self.module = None
    150             else:
    151                 self.testNames = (self.defaultTest,)
    152             self.createTests()
    153         except getopt.error, msg:
    154             self.usageExit(msg)
    155 
    156     def createTests(self):
    157         if self.testNames is None:
    158             self.test = self.testLoader.loadTestsFromModule(self.module)
    159         else:
    160             self.test = self.testLoader.loadTestsFromNames(self.testNames,
    161                                                            self.module)
    162 
    163     def _do_discovery(self, argv, Loader=loader.TestLoader):
    164         # handle command line args for test discovery
    165         self.progName = '%s discover' % self.progName
    166         import optparse
    167         parser = optparse.OptionParser()
    168         parser.prog = self.progName
    169         parser.add_option('-v', '--verbose', dest='verbose', default=False,
    170                           help='Verbose output', action='store_true')
    171         if self.failfast != False:
    172             parser.add_option('-f', '--failfast', dest='failfast', default=False,
    173                               help='Stop on first fail or error',
    174                               action='store_true')
    175         if self.catchbreak != False and installHandler is not None:
    176             parser.add_option('-c', '--catch', dest='catchbreak', default=False,
    177                               help='Catch ctrl-C and display results so far',
    178                               action='store_true')
    179         if self.buffer != False:
    180             parser.add_option('-b', '--buffer', dest='buffer', default=False,
    181                               help='Buffer stdout and stderr during tests',
    182                               action='store_true')
    183         parser.add_option('-s', '--start-directory', dest='start', default='.',
    184                           help="Directory to start discovery ('.' default)")
    185         parser.add_option('-p', '--pattern', dest='pattern', default='test*.py',
    186                           help="Pattern to match tests ('test*.py' default)")
    187         parser.add_option('-t', '--top-level-directory', dest='top', default=None,
    188                           help='Top level directory of project (defaults to start directory)')
    189 
    190         options, args = parser.parse_args(argv)
    191         if len(args) > 3:
    192             self.usageExit()
    193 
    194         for name, value in zip(('start', 'pattern', 'top'), args):
    195             setattr(options, name, value)
    196 
    197         # only set options from the parsing here
    198         # if they weren't set explicitly in the constructor
    199         if self.failfast is None:
    200             self.failfast = options.failfast
    201         if self.catchbreak is None and installHandler is not None:
    202             self.catchbreak = options.catchbreak
    203         if self.buffer is None:
    204             self.buffer = options.buffer
    205 
    206         if options.verbose:
    207             self.verbosity = 2
    208 
    209         start_dir = options.start
    210         pattern = options.pattern
    211         top_level_dir = options.top
    212 
    213         loader = Loader()
    214         self.test = loader.discover(start_dir, pattern, top_level_dir)
    215 
    216     def runTests(self):
    217         if self.catchbreak:
    218             installHandler()
    219         if self.testRunner is None:
    220             self.testRunner = runner.TextTestRunner
    221         if isinstance(self.testRunner, (type, types.ClassType)):
    222             try:
    223                 testRunner = self.testRunner(verbosity=self.verbosity,
    224                                              failfast=self.failfast,
    225                                              buffer=self.buffer)
    226             except TypeError:
    227                 # didn't accept the verbosity, buffer or failfast arguments
    228                 testRunner = self.testRunner()
    229         else:
    230             # it is assumed to be a TestRunner instance
    231             testRunner = self.testRunner
    232         self.result = testRunner.run(self.test)
    233         if self.exit:
    234             sys.exit(not self.result.wasSuccessful())
    235 
    236 main = TestProgram
    237 
    238 def main_():
    239     TestProgram.USAGE = USAGE_AS_MAIN
    240     main(module=None)
    241 
    242