unittest 源代码分析(二)--main.py代码分析

来源:互联网 发布:建筑工地用工人员软件 编辑:程序博客网 时间:2024/05/17 15:36

1 介绍

   main.py是unittest主文件。

2 main.py调用过程

   TestProgram.__init__()  ==>  TestProgram.parseArgs() ==> TestProgram.createTests() ==> TestProgram.runTests()

   __init__() 初始化调用parseArgs()和runTests()

   parseArgs()解析输入参数

   createTests()创建测试用例集合

   runTests()执行测试用例

3 代码和注释

"""Unittest main program"""import sysimport osimport typesfrom . import loader, runnerfrom .signals import installHandler__unittest = True#-h 输出帮助信息FAILFAST     = "  -f, --failfast   Stop on first failure\n"CATCHBREAK   = "  -c, --catch      Catch control-C and display results\n"BUFFEROUTPUT = "  -b, --buffer     Buffer stdout and stderr during test runs\n"# -f  用例遇到失败后停止,不在执行后面的用例# -c  ctrl-c 中断后执行完输出测试结果USAGE_AS_MAIN = """\Usage: %(progName)s [options] [tests]Options:  -h, --help       Show this message  -v, --verbose    Verbose output  -q, --quiet      Minimal output%(failfast)s%(catchbreak)s%(buffer)sExamples:  %(progName)s test_module               - run tests from test_module  %(progName)s module.TestClass          - run tests from module.TestClass  %(progName)s module.Class.test_method  - run specified test method[tests] can be a list of any number of test modules, classes and testmethods.Alternative Usage: %(progName)s discover [options]Options:  -v, --verbose    Verbose output%(failfast)s%(catchbreak)s%(buffer)s  -s directory     Directory to start discovery ('.' default)  -p pattern       Pattern to match test files ('test*.py' default)  -t directory     Top level directory of project (default to                   start directory)For test discovery all test modules must be importable from the toplevel directory of the project."""USAGE_FROM_MODULE = """\Usage: %(progName)s [options] [test] [...]Options:  -h, --help       Show this message  -v, --verbose    Verbose output  -q, --quiet      Minimal output%(failfast)s%(catchbreak)s%(buffer)sExamples:  %(progName)s                               - run default set of tests  %(progName)s MyTestSuite                   - run suite 'MyTestSuite'  %(progName)s MyTestCase.testSomething      - run MyTestCase.testSomething  %(progName)s MyTestCase                    - run all 'test*' test methods                                               in MyTestCase"""#TestProgram是unittest主类调用其他类完成测试class TestProgram(object):    USAGE = USAGE_FROM_MODULE  #帮助信息    # defaults for testing    failfast = catchbreak = buffer = progName = None    def __init__(self, module='__main__', defaultTest=None, argv=None,                    testRunner=None, testLoader=loader.defaultTestLoader,                    exit=True, verbosity=1, failfast=None, catchbreak=None,                    buffer=None):        if isinstance(module, basestring):               #basestring是str和unicode的超类(父类),也是抽象类,因此不能被调用和实例化,但可以被用来判断一个对象是否为str或者unicode的实例            self.module = __import__(module)            #动态加载测试用例文件            for part in module.split('.')[1:]:                self.module = getattr(self.module, part)        else:            self.module = module        if argv is None:            argv = sys.argv        #获取运行case的参数        self.exit = exit        self.failfast = failfast        self.catchbreak = catchbreak        self.verbosity = verbosity        self.buffer = buffer        self.defaultTest = defaultTest        self.testRunner = testRunner        #参数初始化        self.testLoader = testLoader        #初始化创建测试用例集的类        self.progName = os.path.basename(argv[0])        #调用测试用例文件赋值到self.progName        self.parseArgs(argv)        #参数解析函数        self.runTests()        #测试用例运行函数    #输出帮助信息函数    def usageExit(self, msg=None):        if msg:            print msg        usage = {'progName': self.progName, 'catchbreak': '', 'failfast': '',                 'buffer': ''}        if self.failfast != False:            usage['failfast'] = FAILFAST        if self.catchbreak != False:            usage['catchbreak'] = CATCHBREAK        if self.buffer != False:            usage['buffer'] = BUFFEROUTPUT        print self.USAGE % usage        sys.exit(2)    #解析输入参数并生成测试用例    def parseArgs(self, argv):        #调用discover参数加载目录里文件,并生成测试用例集        if len(argv) > 1 and argv[1].lower() == 'discover':            self._do_discovery(argv[2:])            return        import getopt        long_opts = ['help', 'verbose', 'quiet', 'failfast', 'catch', 'buffer']        try:            options, args = getopt.getopt(argv[1:], 'hHvqfcb', long_opts)            for opt, value in options:                if opt in ('-h','-H','--help'):                    self.usageExit()                if opt in ('-q','--quiet'):                    self.verbosity = 0                if opt in ('-v','--verbose'):                    self.verbosity = 2                if opt in ('-f','--failfast'):                    if self.failfast is None:                        self.failfast = True                    # Should this raise an exception if -f is not valid?                if opt in ('-c','--catch'):                    if self.catchbreak is None:                        self.catchbreak = True                    # Should this raise an exception if -c is not valid?                if opt in ('-b','--buffer'):                    if self.buffer is None:                        self.buffer = True                    # Should this raise an exception if -b is not valid?            if len(args) == 0 and self.defaultTest is None:                # 没有指定测试用例                self.testNames = None            elif len(args) > 0:                # 指定测试用例                self.testNames = args                if __name__ == '__main__':                    # to support python -m unittest ...                    self.module = None            else:                self.testNames = (self.defaultTest,)            self.createTests()            #创建测试用例集合        except getopt.error, msg:            self.usageExit(msg)    #创建测试用例集合函数    def createTests(self):        if self.testNames is None:            # 没有指定测试用例加载整个文件做测试集合            self.test = self.testLoader.loadTestsFromModule(self.module)        else:            # 指定使用的测试用例,加载当个测试用例            self.test = self.testLoader.loadTestsFromNames(self.testNames,                                                           self.module)    #将指定目录的文件加载成测试用例集    def _do_discovery(self, argv, Loader=None):        if Loader is None:            Loader = lambda: self.testLoader        # handle command line args for test discovery        self.progName = '%s discover' % self.progName        import optparse        parser = optparse.OptionParser()        parser.prog = self.progName        parser.add_option('-v', '--verbose', dest='verbose', default=False,                          help='Verbose output', action='store_true')        if self.failfast != False:            parser.add_option('-f', '--failfast', dest='failfast', default=False,                              help='Stop on first fail or error',                              action='store_true')        if self.catchbreak != False:            parser.add_option('-c', '--catch', dest='catchbreak', default=False,                              help='Catch ctrl-C and display results so far',                              action='store_true')        if self.buffer != False:            parser.add_option('-b', '--buffer', dest='buffer', default=False,                              help='Buffer stdout and stderr during tests',                              action='store_true')        parser.add_option('-s', '--start-directory', dest='start', default='.',                          help="Directory to start discovery ('.' default)")        parser.add_option('-p', '--pattern', dest='pattern', default='test*.py',                          help="Pattern to match tests ('test*.py' default)")        parser.add_option('-t', '--top-level-directory', dest='top', default=None,                          help='Top level directory of project (defaults to start directory)')        options, args = parser.parse_args(argv)        if len(args) > 3:            self.usageExit()        for name, value in zip(('start', 'pattern', 'top'), args):            setattr(options, name, value)        # only set options from the parsing here        # if they weren't set explicitly in the constructor        if self.failfast is None:            self.failfast = options.failfast        if self.catchbreak is None:            self.catchbreak = options.catchbreak        if self.buffer is None:            self.buffer = options.buffer        if options.verbose:            self.verbosity = 2        start_dir = options.start        pattern = options.pattern        top_level_dir = options.top               loader = Loader()#根据开始目录,匹配格式,顶层目录生成测试用例        self.test = loader.discover(start_dir, pattern, top_level_dir)    #执行测试用例    def runTests(self):        if self.catchbreak:            #注册捕捉信号函数            installHandler()        if self.testRunner is None:            self.testRunner = runner.TextTestRunner        if isinstance(self.testRunner, (type, types.ClassType)):            try:                testRunner = self.testRunner(verbosity=self.verbosity,                                             failfast=self.failfast,                                             buffer=self.buffer)            except TypeError:                # didn't accept the verbosity, buffer or failfast arguments                testRunner = self.testRunner()        else:            # it is assumed to be a TestRunner instance            testRunner = self.testRunner        #根据输入的参数初始化runner类        #调用runner.run运行测试用例        self.result = testRunner.run(self.test)        if self.exit:            sys.exit(not self.result.wasSuccessful())#主函数main = TestProgram


0 0