python自动化测试三部曲之unittest框架的实现

    科技2024-10-08  20

    unittest单元测试框架提供了创建测试用例,测试套件,和批量执行测试用例的方法,在python安装成功后,unittest单元测试框架可以直接导入使用,他属于python的标准库;作为单元测试的框架,unittest单元测试框架也是对程序的最小模块进行的一种敏捷化的测试。在自动化测试i中,我们虽然不需要做白盒测试,但是必须知道所使用语言的单元测试框架,这是因为后面我们测试,就会遇到用例组织的问题,虽然函数式编程和面向对象编程提供了对代码的重构,但是对于所编写的每个测试用例,不可能编写成一个函数来调用执行;利用单元测试框架,可以创建一个类,该类继承unittest的TestCase,这样可以把每个TestCase看成是一个最小的单元,由测试套件组织起来,运行时直接执行即可,同时可引入测试报告。unittest各个组件的关系如果

    TestCase------------------------------->TestFixture(测试固件) | | | TestSuite(测试套件)----------------------->TestRunner(测试执行)-------------------->TestReport(测试报告)

    1 2 3 4 5 # TestCase # 类,必须要继承unittest.TestCase # 一个类class继承 unittest.TestCase,就是一个测试用例。一个TestCase的实例就是一个测试用例,就是一个完整的测试流程。 # 包括测试前环境准备setUp()|setUpClass()、执行代码run()、测试环境后的还原tearDown()|tearDownClass()。 # 继承自unittest.TestCase的类中,测试方法的名称要以test开头。且只会执行以test开头定义的方法(测试用例)。 二、测试固件(TestFixture)

    在unittest单元测试框架中,测试固件用于处理初始化的操作,例如,在对百度的搜索进行测试前,首先需要打开浏览器并且进入百度的首页;测试结束后,需要关闭浏览器;测试固件提哦功能了两种执行形式,一种是每执行一个测试用例,测试固件就会被执行一次;另外一种就不管有多少个用例i,测试固件只会执行一次

    1 2 3 4 5 6 7 8 # 用于一个测试环境的准备和销毁还原。 # 当测试用例每次执行之前需要准备测试环境,每次测试完成后还原测试环境,比如执行前连接数据库、打开浏览器等,执行完成后需要还原数据库、关闭浏览器等操作。 # 这时候就可以启用testfixture。   # setUp():准备环境,执行每个测试用例的前置条件; # tearDown():环境还原,执行每个测试用例的后置条件; # setUpClass():必须使用@classmethod装饰器,所有case执行的前置条件,只运行一次; # tearDownClass():必须使用@classmethod装饰器,所有case运行完后只运行一次; 1、测试固件每次均执行

    unittest单元测试框架提供了名为setUp的tearDown的测试固件。下面,我们通过编写一个例子来看测试固件的执行方式,测试代码如下

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import unittest   class Test1(unittest.TestCase):     # 测试固件之前置条件   def setUp(self):     print("这是前置条件")     # 测试固件之后置条件   def tearDown(self):     print("这是后置条件")     def test_case1(self):     print("test_case1")     def test_case2(self):     print("test_case2")     if __name__ == '__main__':   unittest.main(verbosity=2) 执行结果如下

    他的执行顺序是先执行setUp方法,在执行具体的用例,最后执行tearDown方法

    2、测试固件只执行一次

    钩子方法setUp和tearDown虽然经常使用,但是在自动化测试中,一个系统的测试用例多达上千条,每次都执行一次的setUp和tearDown方法会耗费大量的性能,在unittest单元测试框架中还可以使用另外一种测试固件来解决这一问题,他就是setUpClass和tearDownClass方法,该测试固件方法是类方法,需要在方法上面加装饰器@classmethod,使用该测试固件,不管有多少个用例,测试固件只执行一次,具体代码如下

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import unittest   class Test1(unittest.TestCase):   # def setUp(self):   #   print("这是前置条件")   #   # def tearDown(self):   #   print("这是后置条件")     @classmethod   def setUpClass(cls):     print("这是类方法前置条件")     @classmethod   def tearDownClass(cls):     print("这是类方法后置条件")     def test_case1(self):     print("test_case1")     def test_case2(self):     print("test_case2")     if __name__ == '__main__':   unittest.main(verbosity=2) 结果如下

    3、两种测试固件并存

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import unittest     class Test1(unittest.TestCase):   def setUp(self):     print("这是前置条件")     def tearDown(self):     print("这是后置条件")     @classmethod   def setUpClass(cls):     print("这是类方法前置条件")     @classmethod   def tearDownClass(cls):     print("这是类方法后置条件")     def test_case1(self):     print("test_case1")     def test_case2(self):     print("test_case2")     if __name__ == '__main__':   unittest.main(verbosity=2) 执行结果如下

    结果表明,先执行被@classmethod装饰器装饰的测试固件,在执行普通的测试固件

    三、测试执行

    在以上事例中,可以看到测试用例的执行是在主函数中,unittest调用的是main,代码如下,TestProjram还是一个类,再来看该类的构造函数,代码如下

    1 main = TestProgram TestProjram还是一个类,再来看该类的构造函数,代码如下

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 class TestProgram(object):   """A command-line program that runs a set of tests; this is primarily     for making test modules conveniently executable.   """   # defaults for testing   module=None   verbosity = 1   failfast = catchbreak = buffer = progName = warnings = None   _discovery_parser = 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, warnings=None, *, tb_locals=False):     if isinstance(module, str):       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       self.exit = exit     self.failfast = failfast     self.catchbreak = catchbreak     self.verbosity = verbosity     self.buffer = buffer     self.tb_locals = tb_locals     if warnings is None and not sys.warnoptions:       # even if DeprecationWarnings are ignored by default       # print them anyway unless other warnings settings are       # specified by the warnings arg or the -W python flag       self.warnings = 'default'     else:       # here self.warnings is set either to the value passed       # to the warnings args or to None.       # If the user didn't pass a value self.warnings will       # be None. This means that the behavior is unchanged       # and depends on the values passed to -W.       self.warnings = warnings     self.defaultTest = defaultTest     self.testRunner = testRunner     self.testLoader = testLoader     self.progName = os.path.basename(argv[0])     self.parseArgs(argv)     self.runTests() 在unittest模块中包含的main方法,可以方便的将测试模块转变为可以运行的测试脚本。main使用unittest.TestLoader类来自动查找和加载模块内的测试用例,TestProgram类中的该部分的代码如下

    1 2 3 4 5 6 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) 在执行测试用例时候,在main方法中加入了verbosity=2,代码如下

    1 2 if __name__ == '__main__':   unittest.main(verbosity=2) 下面解释一下verbosity部分,在verbosity中默认是1。0代表执行的测试总数和全局结果,2代表详细的信息

    四、测试套件,TestSuite

    1 2 3 4 5 # TestSuite # 上述简单的测试会产生两个问题,可不可以控制test测试用例的执行顺序?若不想执行某个测试用例,有没有办法可以跳过? # 对于执行顺序,默认按照test的 A-Z、a-z的方法执行。若要按自己编写的用例的先后关系执行,需要用到testSuite。 # 把多个测试用例集合起来,一起执行,就是testSuite。testsuite还可以包含testsuite。 # 一般通过addTest()或者addTests()向suite中添加。case的执行顺序与添加到Suite中的顺序是一致的。 1、直接执行案例

    我们在func.py这个文件中定义加减乘除4个测试函数

    1 2 3 4 5 6 7 8 9 10 #Auther Bob #--*--conding:utf-8 --*-- def add(a,b):   return a + b def minus(a,b):   return a - b def multi(a,b):   return a * b def divide(a,b):   return a / b

    然后在myunittest.py文件中定义我们的测试代码,这里用到了断言,我们后面会介绍

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 from test1 import func   class Test2(unittest.TestCase):   def setUp(self):     print("前置条件")     def tearDown(self):     print("后置条件")     def test_add(self):     self.assertEqual(3,func.add(1,2))     def test_minus(self):     self.assertEqual(4,func.minus(5,1))     def test_multi(self):     self.assertEqual(4,func.multi(2,2))     def test_divide(self):     self.assertEqual(10,func.divide(100,10))     if __name__ == '__main__':   unittest.main(verbosity=2) 执行结果如下

    2、添加案例到测试套件中

    上述简单的测试会产生两个问题,可不可以控制test测试用例的执行顺序?若不想执行某个测试用例,有没有办法可以跳过?对于执行顺序,默认按照test的 A-Z、a-z的方法执行。若要按自己编写的用例的先后关系执行,需要用到testSuite。把多个测试用例集合起来,一起执行,就是testSuite。testsuite还可以包含testsuite。一般通过addTest()或者addTests()向suite中添加。case的执行顺序与添加到Suite中的顺序是一致的。 如果用到测试套件TestSuite,则需要先写好测试代码,但是先不要执行

    Processed: 0.011, SQL: 8