Python-34-单元测试

倖福魔咒の 提交于 2019-11-26 19:53:43

【=看project_unittest项目=====】

  1. unittest核心工作原理

    unittest中最核心的四个概念是:test case(测试用例),test
    suite(测试集),test runner,test fixture

    • 一个TestCase的实例就是一个测试用例。什么是测试用例呢?就是一个完整的测试流程,包括测试前准备环境的搭建(setUp),执行测试代码(run),以及测试后环境的还原(tearDown)。元测试(unit test)的本质也就在这里,一个测试用例是一个完整的测试单元,通过运行这个测试单元,可以对某一个问题进行验证。
    • 而多个测试用例集合在一起,就是TestSuite,而且TestSuite也可以嵌套TestSuite。
      TestLoader是用来加载TestCase到TestSuite中的,其中有几个loadTestsFrom__()方法,就是从各个地方寻找TestCase,创建它们的实例,然后add到TestSuite中,再返回一个TestSuite实例。
    • TextTestRunner是来执行测试用例的,其中的run(test)会执行TestSuite/TestCase中的run(result)方法。
      测试的结果会保存到TextTestResult实例中,包括运行了多少测试用例,成功了多少,失败了多少等信息。
    • 而对一个测试用例环境的搭建和销毁,是一个fixture。

    unittest的流程:写好TestCase,然后由TestLoader加载TestCase到TestSuite,然后由TextTestRunner来运行TestSuite,运行的结果保存在TextTestResult中,我们通过命令行或者unittest.main()执行时,main会调用TextTestRunner中的run来执行,或者我们可以直接通过TextTestRunner来执行用例。

  2. TestCase代码

     #  part1/methods.py==========================
     
     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
     
     
     #  testCases/test_part1/case_methods.py========================
     
     import unittest
     from part1.methods import *
     
     class TestMethods(unittest.TestCase):
     
         # 测试方法必须以 testCases 开头
         def test_add(self):
             self.assertEqual(3, add(1, 2))
             self.assertNotEqual(2, add(2, 2))
     
         def test_minus(self):
             self.assertEqual(1, minus(3, 2))
     
         def test_multi(self):
             self.assertEqual(6, multi(2, 3))
     
         def test_divide(self):
             self.assertEqual(2, divide(6, 3))
             self.assertEqual(2.5, divide(5, 2))
     
     if __name__ == '__main__':
         unittest.main()
    

    一个class继承了unittest.TestCase,便是一个测试用例,但如果其中有多个以 test 开头的方法,那么每有一个这样的方法,在load的时候便会生成一个TestCase实例,如:一个class中有四个test_xxx方法,最后在load到suite中时也有四个测试用例。

    写好TestCase,然后由TestLoader加载TestCase到TestSuite,然后由TextTestRunner来运行TestSuite,运行的结果保存在TextTestResult中,我们通过命令行或者unittest.main()执行时,main会调用TextTestRunner中的run来执行,或者我们可以直接通过TextTestRunner来执行用例。这里加个说明,在Runner执行时,默认将执行结果输出到控制台,我们可以设置其输出到文件,在文件中查看结果(HTMLTestRunner,通过它可以将结果输出到HTML中,生成漂亮的报告,它跟TextTestRunner是一样的,从名字就能看出来,这个我们后面再说)。

  3. TestSuite

    上面的代码示例了如何编写一个简单的测试,但有两个问题,我们怎么控制用例执行的顺序呢?(这里的示例中的几个测试方法并没有一定关系,但之后你写的用例可能会有先后关系,需要先执行方法A,再执行方法B),我们就要用到TestSuite了。我们添加到TestSuite中的case是会按照添加的顺序执行的。

    问题二是我们现在只有一个测试文件,我们直接执行该文件即可,但如果有多个测试文件,怎么进行组织,总不能一个个文件执行吧,答案也在TestSuite中。

     import unittest
     from testCases.test_part1.case_methods import TestMethods
     from testCases.test_part1.case_user import TestUser
     
     if __name__ == '__main__':
         # 测试集合
         suite = unittest.TestSuite()
     
         # # 1. 多个加入  **
         # tests = [TestMethods("test_add"), TestMethods("test_minus"), TestMethods("test_divide"), TestUser("test_login"),TestUser("test_pay")]
         # suite.addTests(tests)
     
         # # 2. 单个加入
         # suite.addTest(TestMethods("test_multi"))
     
     
         #!!!ps: 当使用parameterized传参时,必须用类
         # 3. 直接加入模块中的 test Case 类 --FromName加入一个类,FromNames加入类列表  **
         suite.addTests(unittest.TestLoader().loadTestsFromNames(['case_methods.TestMethods', 'case_user.TestUser']))
     
     
         # # 测试执行对象
         # # verbosity 测试报告的描述详细程度,0 是简单报告、1 是一般报告、2 是详细报告。
         # runner = unittest.TextTestRunner(verbosity=2)
         # runner.run(suite)
     
         # 写入测试文件
         from datetime import datetime
         with open('UnittestTextReport.txt', 'a') as f:
             runner = unittest.TextTestRunner(stream=f, verbosity=3)
             runner.run(suite)
     
             f.write(datetime.now().strftime('%Y-%m_%d %H:%M:%S')+'\n'*10)
    

    用TestLoader的方法是无法对case进行排序的,同时,suite中也可以套suite。

  4. 将测试结果写入文件

     import unittest
     from test.test_func.test_methods_test_case import TestMethods
     
     if __name__ == '__main__':
     
         suite = unittest.TestSuite()
     
         suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestMethods))
     
         with open('UnittestTextReport1.txt','a') as f:
             runner = unittest.TextTestRunner(stream=f, verbosity=2)
             runner.run(suite)
    
  5. unittest中的参数化

    !!!ps: 当使用parameterized传参时,必须用类

      ''' 
      # 3.直接加入模块中的 test Case 类--FromName加入一个类,FromNames加入类列表 **
     suite.addTests(unittest.TestLoader().loadTestsFromNames(['case_methods.TestMethods', 'case_user.TestUser']))
     '''
    

    pip3 install nose_parameterized

     '''
      class TestUser(unittest.TestCase):
      
         @parameterized.expand(
             [
                 [Person('admin','123456'), '1001'],
                 [Person('admin','`123'), '4004'],
                 [Person('boss','123456'), '4005']
             ]
         )
     
         def test_login(self, user, flag):
             self.assertEqual(flag, login(user))
     
     
         def test_pay(self):
             self.assertEqual(True, pay(None, None))
     '''
    
  6. setUp() tearDown()

    setUp() 和 tearDown() 两个方法(其实是重写了TestCase的这两个方法),这两个方法在每个测试方法执行前以及执行后执行一次,setUp用来为测试准备环境,tearDown用来清理环境,已备之后的测试。

    生命周期方法:一定会执行,new\init\setUp\tearDown

    setUP():当一个实例出现时,一定会执行,即在每次执行case前执行一次

    tearDown():当一个实例结束时,一定会执行,即在每次执行case后执行一次

    setUpClass():类方法,所有case执行之前执行一次,即准备一次环境

    tearDownClass():类方法,所有case结束之后执行一次,即清理一次环境

    !!! 注意:setUp() tearDown() setUpClass() tearDownClass() 必须放在 @parameterized.expand() 前面, 否则报错

     '''
     class TestUser(unittest.TestCase):
         def setUp(self):
             print('before...')
     
         def tearDown(self):
             print('after... ')
     
         # @classmethod
         # def setUpClass(cls):
         #     print('before...only one')
         #
         # @classmethod
         # def tearDownClass(cls):
         #     print('after...only one')
     
         @parameterized.expand(
             [
                 [Person('admin','123456'), '1001'],
                 [Person('admin','`123'), '4004'],
                 [Person('boss','123456'), '4005']
             ]
         )
     
         def test_login(self, user, flag):
             self.assertEqual(flag, login(user))
     
     
         def test_pay(self):
             self.assertEqual(True, pay(None, None))
     '''
    
  7. 跳过skip装饰器

    skip装饰器一共有三个

     1. unittest.skip(reason)
     
     2. unittest.skipIf(condition, reason)		
     3. unittest.skipUnless(condition, reason)
     
     skip无条件跳过,skipIf当condition为True时跳过,skipUnless当condition为False时跳过。
     
     	@unittest.skipIf(num>0,"num的值没有大于零")  #此处调用类属性不需要加类名
     	def test_add(self):
    
    
     class TestMethods(unittest.TestCase):
    
         # 测试方法必须以 testCases 开头
         def test_add(self):
             self.assertEqual(3, add(1, 2))
             self.assertNotEqual(2, add(2, 2))
     
         def test_minus(self):
             self.assertEqual(1, minus(3, 2))
     
         @unittest.skip("i don't want to run this case")
         # @unittest.skipIf(True, "i don't want to run this case--skipIf")
         # @unittest.skipUnless(False, "i don't want to run this case-- skipUnless")
         def test_multi(self):
             self.assertEqual(6, multi(2, 3))
     
         def test_divide(self):
             self.assertEqual(2, divide(6, 3))
             self.assertEqual(2.5, divide(5, 2))
    
  8. 用HTMLTestRunner输出漂亮的HTML报告

    HTMLTestRunner是一个第三方的unittest HTML报告库,首先我们下载HTMLTestRunner.py,并放到当前目录下,或者你的’C:\Python27\Lib’下,就可以导入运行了。

    下载地址:

    官方原版

    修改版

    Python3.x版本:

     from testCases.test_part1 import HTMLTestRunner
     
     if __name__ == '__main__':
     
         # 测试集合
         suite = unittest.TestSuite()
         
         suite.addTests(unittest.TestLoader().loadTestsFromNames(['case_methods.TestMethods', 'case_user.TestUser']))
    
         # 用HTMLTestRunner输出漂亮的HTML报告
         with open('UnittestTextReport.html', 'w',encoding='utf-8') as f:
             runner = HTMLTestRunner.HTMLTestRunner(
                 stream=f,
                 title='<测试报告>',
                 description='This demonstrates the report output by HTMLTestRunner.'
             )
             runner.run(suite)
    
  9. https://blog.csdn.net/column/details/12694.html?&page=2

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!