unittest之TestSuite类详解

unittest之TestSuite类详解
绝缘法兰TestSuite
测试套件类,如何理解测试套件这个概念呢,从它的类定义来看,可以理解为:多个独⽴的测试⽤例(test case)或者多个独⽴的测试套
件(test suite,可以理解为⼦套件)可以构成⼀个测试套件,那么我们写好了⼀个⽤例之后,如果去构建⼀个测试套件呢。下⾯介绍⼏种
构建测试套件的⽅法:
1. 通过unittest.TestSuite()类直接构建,或者通过TestSuite实例的addTests、addTest⽅法构建
2. 通过unittest.TestLoader类的discover、loadTestsFromTestCase、loadTestsFromModule、loadTestsFromName、loadTestsFromNames这五个⽅法去构建
3. 通过unittest.makeSuite()、unittest.findTestCases()这两个⽅法去构建
下⾯我们分别对以上⼏种⽅法分别举⼀个例⼦:我们先写好⼀个TestCase:
#使⽤unittest.TestSuite()类直接构建,或者通过TestSuite实例的addTests、addTest⽅法构建
import unittest
class UserCase(unittest.TestCase):
def testAddUser(self):
print("add a user")
def testDelUser(self):
print("delete a user")
if __name__ == '__main__':
suite = unittest.TestSuite(map(UserCase,['testAddUser','testDelUser']))
suite2 = unittest.TestSuite()
suite2.addTests(map(UserCase,['testAddUser','testDelUser']))
suite3 = unittest.TestSuite()
suite3.addTest(UserCase('testAddUser'))
suite3.addTest(UserCase('testDelUser'))
#通过unittest.TestLoader类的discover、loadTestsFromTestCase、loadTestsFromModule、loadTestsFromName、loadTestsFromNames这五个⽅法去构建import unittest
class UserCase(unittest.TestCase):
def testAddUser(self):
print("add a user")
def testDelUser(self):
print("delete a user")
if __name__ == '__main__':
module = __import__(__name__)
suite = unittest.TestLoader().discover('.','unittest_user.py') #unittest_user.py
suite2 = unittest.TestLoader().loadTestsFromTestCase(UserCase)
suite3 = unittest.TestLoader().loadTestsFromModule(module)
#loadTestsFromName、loadTestsFromNames暂时不举例了,参数类型较多,不便举例,可以⾃⾏阅读其代码
#通过unittest.makeSuite()、unittest.findTestCases()这两个⽅法去构建
import unittest
class UserCase(unittest.TestCase):
def testAddUser(self):
print("add a user")
def testDelUser(self):
print("delete a user")
if __name__ == '__main__':
module = __import__(__name__)
suite = unittest.makeSuite(UserCase,prefix='test')
suite2 = unittest.findTestCases(module,prefix='test')
上⾯介绍了创建TestSuite的⼏种⽅法,其实这⼏种⽅法最终都脱离不了通过TestSuite去创建测试集,不信? 那我们就拿TestLoader()的loadTestsFromTestCase来验证⼀下是不是这样⼦的。
我们先看loadTestsFromTestCase的⽅法实现:
class TestLoader(object):
"""
This class is responsible for loading tests according to various criteria
and returning them wrapped in a TestSuite
"""
testMethodPrefix = 'test'
sortTestMethodsUsing = cmp
安全带插销suiteClass = suite.TestSuite
毛刷制作
_top_level_dir = None
def loadTestsFromTestCase(self, testCaseClass):
"""Return a suite of all test cases contained in testCaseClass"""
if issubclass(testCaseClass, suite.TestSuite):
raise TypeError("Test cases should not be derived from TestSuite." \
" Maybe you meant to derive from TestCase?")
testCaseNames = TestCaseNames(testCaseClass)
if not testCaseNames and hasattr(testCaseClass, 'runTest'):
testCaseNames = ['runTest']
loaded_suite = self.suiteClass(map(testCaseClass, testCaseNames))
return loaded_suite
我们注意到类⾥⾯的⼏个变量:
testMethodPrefix = ‘test’
sortTestMethodsUsing = cmp
suiteClass = suite.TestSuite
第⼀句是⽤来过滤我们的测试⽅法,即默认的以test开头的⽅法
第⼆句是⽤来对我们的测试⽅法名排序的⽅法cmp
第三句是对suiteClass赋值,即TestSuite类
loadTestsFromTestCase的参数是⼀个TestCaseClass,就是我们编写的测试类的类名,
重要的⼀⾏代码:
testCaseNames = TestCaseNames(testCaseClass)
这是⼲嘛的呢,读者们可以阅读⼀下getTestCaseNames的⽅法的实现,可以看出它是在获取TestCaseClass中所有以“test”开头的⽅法名,并且以字符串排序的⽅式排好序后并返回⼀个列表。然后还有⼀⾏重要的代码:
loaded_suite = self.suiteClass(map(testCaseClass, testCaseNames))
这就是我刚刚上⾯说的“所有的构建TestSuite⽅法都脱离不了通过TestSuite去创建测试集”的根源,loaded_suite最终的的值就是TestSuite的实例
有⼈可能会问,我们最终运⾏的是⼀个个的测试⽤例,⽽不是⼀整个测试集,既然我们是创建的测试集,那它是如何去运⾏我们的测试⽤例的呢。别着急,答案马上揭晓。
测试集TestSuite类中跟TestCase⼀样也有⼀个run⽅法,我们先看代码:
class TestSuite(BaseTestSuite):
def run(self, result, debug=False):
topLevel = False
if getattr(result, '_testRunEntered', False) is False:
result._testRunEntered = topLevel = True
for test in self:
if result.shouldStop:
break
if _isnotsuite(test):
self._tearDownPreviousClass(test, result)
self._handleModuleFixture(test, result)
弯曲刚度
self._handleClassSetUp(test, result)
result._previousTestClass = test.__class__
if (getattr(test.__class__, '_classSetupFailed', False) or
getattr(result, '_moduleSetUpFailed', False)):
continue
if not debug:
test(result)
else:
test.debug()
if topLevel:
self._tearDownPreviousClass(None, result)
self._handleModuleTearDown(result)
result._testRunEntered = False
obd数据
return result
注意TestSuite是继承BaseTestSuite类的,并且重写了BaseTestSuite类run⽅法。并且参数是result,这跟TestCase类的run⽅法的参数⼀样,后⾯的debug参数我们先不关注。
前⾯三⾏代码我们也先忽略,我们来看中间部分的代码:
for test in self
第⼀句就是循环,迭代器的⽤法,为什么说是迭代器呢,因为BaseTestSuite类实现了iter魔术⽅法。我们可以看⼀下:
def__iter__(self):
return iter(self._tests)
这下知道为什么可以循环了吧,并且每⼀次迭代返回的是⼀个test,这个test是什么呢,就是我们创建测试套件时往⾥⾯添加的TestCase 的实例或TestSuite的实例。
接着往下看:
if _isnotsuite(test):
self._tearDownPreviousClass(test, result)
self._handleModuleFixture(test, result)
self._handleClassSetUp(test, result)
result._previousTestClass = test.__class__
if (getattr(test.__class__, '_classSetupFailed', False) or
getattr(result, '_moduleSetUpFailed', False)):
continue
这段代码是⼲嘛的呢,我总结了⼀下,是处理setUpClass和TearDownClass部分的逻辑(⾥⾯的⽅法的源码较多,暂时就不⼀⼀解释了),如果setUpClass失败,则continue跳出本次循环继续执⾏下⼀个⽤例,包括==后⾯测试⽤例的执⾏和TearDownClass的执⾏==
(所以如果我们的⽤例⾥⾯有重写了setUpClass,并且失败了,是不会继续往下执⾏的)
继续往下读代码,如果setUpClass没有失败,则继续执⾏下⾯的代码:
if not debug:
test(result)
else:
test.debug()
上⾯我们说过这个test是我们实例化的⼀个TestCase类或TestSuite类,假如这个test就是TestCase类的实例吧。然后test(result)这句是⼲嘛的呢,还记得TestCase类⾥⾯的run⽅法吗,没错,这句话就是调⽤的TestCase类⾥⾯的run⽅法去执⾏⽤例的。这下明⽩了TestSuite是怎样去执⾏我们的TestCase了吧。
简单总结⼀下就是,测试套件(TestSuite)的执⾏是通过它的run⽅法,⽽它的run⽅法⼜会去调⽤每⼀个⽤例(TestCase)的run⽅法。这样就实现了⽤例的执⾏
不知道⼤家有没有注意到,TestCase和TestSuite的run⽅法中有⼀个⽐较明显的区别:
在TestCase中的run⽅法没有去处理setUpClass和TearDownClass部分的逻辑代码,⽽在TestSuite的run⽅法中才有处理setUpClass 和TearDownClass部分的逻辑代码。所以这个地⽅是有⼀些区别的。在本篇⽂章的最后的 [补充部分] 我举例说明⼀下他们执⾏后的不同。
还有⼀⼩部分代码,已经⽆关紧要了,也是处理我们写的测试⽤例类的TearDownClass部分的:
if topLevel:
self._tearDownPreviousClass(None, result)
self._handleModuleTearDown(result)
result._testRunEntered = False
return result
好了,我们的测试套件TestSuite分析到这⾥就差不多结束了,写的有些烂,希望⼤家能有所收获吧。
下⼀篇的我会继续分析TextTestRunner类。期待中。。。
[补充部分]:
TestCase和TestSuite的run⽅法的不同点:
#unittest_prac.py
import sys
import unittest
class UserCase(unittest.TestCase):
@classmethod
def setUpClass(cls):
print('setUpClass')
def setUp(self):
print("setup")
def testAddUser(self):
print("add a user")
def testDelUser(self):
print("delete a user")
def tearDown(self):
print('teardown')
@classmethod
def tearDownClass(cls):
print('tearDownClass')
if __name__ == '__main__':
#实例化⼀个TextTestResult类
result = unittest.TextTestResult(sys.stdout,'test result',1)
suite = unittest.TestSuite(map(UserCase,['testAddUser']))
suite.run(result)
testcase = UserCase('testAddUser')
testcase.run(result)
C:\software\PythonWorkspace>python unittest_prac.py
线切setUpClass
setup
add a user
teardown
.tearDownClass
setup
add a user
teardown
.
可以很明显的看到,TestSuite的run⽅法执⾏setUpClass和tearDownClass,但TestCase的run⽅法没有执⾏setUpClass和tearDownClass

本文发布于:2024-09-25 21:19:48,感谢您对本站的认可!

本文链接:https://www.17tex.com/tex/2/104177.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:测试   套件   部分
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议