Home | History | Annotate | Download | only in unittest
      1 """Unittest main program"""
      2 
      3 import sys
      4 import os
      5 import types
      6 
      7 from . import loader, runner
      8 from .signals import installHandler
      9 
     10 __unittest = True
     11 
     12 FAILFAST     = "  -f, --failfast   Stop on first failure\n"
     13 CATCHBREAK   = "  -c, --catch      Catch control-C and display results\n"
     14 BUFFEROUTPUT = "  -b, --buffer     Buffer stdout and stderr during test runs\n"
     15 
     16 USAGE_AS_MAIN = """\
     17 Usage: %(progName)s [options] [tests]
     18 
     19 Options:
     20   -h, --help       Show this message
     21   -v, --verbose    Verbose output
     22   -q, --quiet      Minimal output
     23 %(failfast)s%(catchbreak)s%(buffer)s
     24 Examples:
     25   %(progName)s test_module               - run tests from test_module
     26   %(progName)s module.TestClass          - run tests from module.TestClass
     27   %(progName)s module.Class.test_method  - run specified test method
     28 
     29 [tests] can be a list of any number of test modules, classes and test
     30 methods.
     31 
     32 Alternative Usage: %(progName)s discover [options]
     33 
     34 Options:
     35   -v, --verbose    Verbose output
     36 %(failfast)s%(catchbreak)s%(buffer)s  -s directory     Directory to start discovery ('.' default)
     37   -p pattern       Pattern to match test files ('test*.py' default)
     38   -t directory     Top level directory of project (default to
     39                    start directory)
     40 
     41 For test discovery all test modules must be importable from the top
     42 level directory of the project.
     43 """
     44 
     45 USAGE_FROM_MODULE = """\
     46 Usage: %(progName)s [options] [test] [...]
     47 
     48 Options:
     49   -h, --help       Show this message
     50   -v, --verbose    Verbose output
     51   -q, --quiet      Minimal output
     52 %(failfast)s%(catchbreak)s%(buffer)s
     53 Examples:
     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 
     61 
     62 
     63 class TestProgram(object):
     64     """A command-line program that runs a set of tests; this is primarily
     65        for making test modules conveniently executable.
     66     """
     67     USAGE = USAGE_FROM_MODULE
     68 
     69     # defaults for testing

     70     failfast = catchbreak = buffer = progName = None
     71 
     72     def __init__(self, module='__main__', defaultTest=None, argv=None,
     73                     testRunner=None, testLoader=loader.defaultTestLoader,
     74                     exit=True, verbosity=1, failfast=None, catchbreak=None,
     75                     buffer=None):
     76         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
     86         self.failfast = failfast
     87         self.catchbreak = catchbreak
     88         self.verbosity = verbosity
     89         self.buffer = buffer
     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
    100         usage = {'progName': self.progName, 'catchbreak': '', 'failfast': '',
    101                  'buffer': ''}
    102         if self.failfast != False:
    103             usage['failfast'] = FAILFAST
    104         if self.catchbreak != False:
    105             usage['catchbreak'] = CATCHBREAK
    106         if self.buffer != False:
    107             usage['buffer'] = BUFFEROUTPUT
    108         print self.USAGE % usage
    109         sys.exit(2)
    110 
    111     def parseArgs(self, argv):
    112         if len(argv) > 1 and argv[1].lower() == 'discover':
    113             self._do_discovery(argv[2:])
    114             return
    115 
    116         import getopt
    117         long_opts = ['help', 'verbose', 'quiet', 'failfast', 'catch', 'buffer']
    118         try:
    119             options, args = getopt.getopt(argv[1:], 'hHvqfcb', long_opts)
    120             for opt, value in options:
    121                 if opt in ('-h','-H','--help'):
    122                     self.usageExit()
    123                 if opt in ('-q','--quiet'):
    124                     self.verbosity = 0
    125                 if opt in ('-v','--verbose'):
    126                     self.verbosity = 2
    127                 if opt in ('-f','--failfast'):
    128                     if self.failfast is None:
    129                         self.failfast = True
    130                     # Should this raise an exception if -f is not valid?

    131                 if opt in ('-c','--catch'):
    132                     if self.catchbreak is None:
    133                         self.catchbreak = True
    134                     # Should this raise an exception if -c is not valid?

    135                 if opt in ('-b','--buffer'):
    136                     if self.buffer is None:
    137                         self.buffer = True
    138                     # Should this raise an exception if -b is not valid?

    139             if len(args) == 0 and self.defaultTest is None:
    140                 # createTests will load tests from self.module

    141                 self.testNames = None
    142             elif len(args) > 0:
    143                 self.testNames = args
    144                 if __name__ == '__main__':
    145                     # to support python -m unittest ...

    146                     self.module = None
    147             else:
    148                 self.testNames = (self.defaultTest,)
    149             self.createTests()
    150         except getopt.error, msg:
    151             self.usageExit(msg)
    152 
    153     def createTests(self):
    154         if self.testNames is None:
    155             self.test = self.testLoader.loadTestsFromModule(self.module)
    156         else:
    157             self.test = self.testLoader.loadTestsFromNames(self.testNames,
    158                                                            self.module)
    159 
    160     def _do_discovery(self, argv, Loader=loader.TestLoader):
    161         # handle command line args for test discovery

    162         self.progName = '%s discover' % self.progName
    163         import optparse
    164         parser = optparse.OptionParser()
    165         parser.prog = self.progName
    166         parser.add_option('-v', '--verbose', dest='verbose', default=False,
    167                           help='Verbose output', action='store_true')
    168         if self.failfast != False:
    169             parser.add_option('-f', '--failfast', dest='failfast', default=False,
    170                               help='Stop on first fail or error',
    171                               action='store_true')
    172         if self.catchbreak != False:
    173             parser.add_option('-c', '--catch', dest='catchbreak', default=False,
    174                               help='Catch ctrl-C and display results so far',
    175                               action='store_true')
    176         if self.buffer != False:
    177             parser.add_option('-b', '--buffer', dest='buffer', default=False,
    178                               help='Buffer stdout and stderr during tests',
    179                               action='store_true')
    180         parser.add_option('-s', '--start-directory', dest='start', default='.',
    181                           help="Directory to start discovery ('.' default)")
    182         parser.add_option('-p', '--pattern', dest='pattern', default='test*.py',
    183                           help="Pattern to match tests ('test*.py' default)")
    184         parser.add_option('-t', '--top-level-directory', dest='top', default=None,
    185                           help='Top level directory of project (defaults to start directory)')
    186 
    187         options, args = parser.parse_args(argv)
    188         if len(args) > 3:
    189             self.usageExit()
    190 
    191         for name, value in zip(('start', 'pattern', 'top'), args):
    192             setattr(options, name, value)
    193 
    194         # only set options from the parsing here

    195         # if they weren't set explicitly in the constructor

    196         if self.failfast is None:
    197             self.failfast = options.failfast
    198         if self.catchbreak is None:
    199             self.catchbreak = options.catchbreak
    200         if self.buffer is None:
    201             self.buffer = options.buffer
    202 
    203         if options.verbose:
    204             self.verbosity = 2
    205 
    206         start_dir = options.start
    207         pattern = options.pattern
    208         top_level_dir = options.top
    209 
    210         loader = Loader()
    211         self.test = loader.discover(start_dir, pattern, top_level_dir)
    212 
    213     def runTests(self):
    214         if self.catchbreak:
    215             installHandler()
    216         if self.testRunner is None:
    217             self.testRunner = runner.TextTestRunner
    218         if isinstance(self.testRunner, (type, types.ClassType)):
    219             try:
    220                 testRunner = self.testRunner(verbosity=self.verbosity,
    221                                              failfast=self.failfast,
    222                                              buffer=self.buffer)
    223             except TypeError:
    224                 # didn't accept the verbosity, buffer or failfast arguments

    225                 testRunner = self.testRunner()
    226         else:
    227             # it is assumed to be a TestRunner instance

    228             testRunner = self.testRunner
    229         self.result = testRunner.run(self.test)
    230         if self.exit:
    231             sys.exit(not self.result.wasSuccessful())
    232 
    233 main = TestProgram
    234