unittest测试框架学习和源码走读(2)
III.测试驱动模块runner.py
runner模块主要功能是:
*.初始化result将测试结果记录和处理转交给result模块;(详参后续result模块lifecycle)
*.启动测试套运行, 将run动作传递给TestSuit模块的__call__函数;
*.统计result结果, 向标准输出和标准错误打印测试结论.
IV.测试嗅探模块load.py
该模块的功能是通过module动态导入特性, 反射并匹配出符合规则的测试用例并组织成测试套.
输入是python模块&文件路径&点分模块, 输出为TestSuit模块.
仍然以demo.py为例子, 在main.py中TestProgram.createTests方法调用loadTestsFromModule
# 构造函数已将load初始化为默认值load.defaultLoader def createTests(self): if self.testNames is None: # self.testNames == None self.test = self.testLoader.loadTestFromModule(self.module) else: self.test = self.testLoader.LoadTestsFromNames(self.testName, self.module)
导入测试用例, loadTestsFromModule通过dir反射模块的属性和方法, 通过类型检查过滤出case.TestCase的子类.
1 def loadTestsFromTestCase(self. testCaseClass): 2 testCaseNames = self.getTestCaseNames(testCaseClass) 3 if not testCaseNames and hasattr(testCaseClass, 'runTest'): 4 testCaseNames = ['runTest'] 5 load_suite = self.suitClass(map(testCaseClass, testCaseNames)) 6 return load_suite 7 8 9 def loadTestsFromModule(self, module, use_load_tests=True): 10 tests=[] 11 for name in dir(module): 12 obj = getattr(module, name) 13 if isinstance(obj, type) and issubclass(obj, case.TestCase): 14 tests.append(self.looadTestsFromTestCase(obj))
然后将子类转交给loadTestsFromTestCase方法.loadTestsFromTestCase依样画葫芦, getTestCaseNames通过dir反射过滤出以test*开头的可执行的模块(方法)名.
值得强调的是, 对于函数式用例case.FunctionTestCase并没有匹配test*开头的入口. 绕一下, 调用了FunctionTestCse的runTest方法, FunctionTestCase.runTest函
数又反过来调用testFunc本身, 将执行权限转交给函数.
导入测试套的操作很妖娆, 非常的python
loaded_suit = self.suitClass( map(testCaseClass, testCaseNames) ) '''' ie. func_list = map(testCaseClass, testCaseNames) map函数调用testCaseClass的构造函数__init__, 实例化test_xx测试用例方法. 至此, 可执行的测试用例实例化, 待执行. load_suit = self.suitClass(func_list) '''
loadTestsFromModule的输出为suite.TestSuite的实例, suite.TestSuite._tests=[<TestStringMethods.test_upper, method>, ...]