zoukankan      html  css  js  c++  java
  • unittest学习

    unittest的四大特点

    1. TestCase:测试用例。所有的用例都是直接继承与UnitTest.TestCase类。

    2. TestFixture:测试固件。setUp和tearDown分别作为前置条件和后置条件。主要用于初始化测试用例和管理用例执行结束后的资源释放。

    3. TestSuite和TestRunner:测试套件和测试运行器。

    4. 断言:在unittest中封装好了成熟的断言,可以直接调用。

    unittest基本用法

    • 语法规则

      • unittest中,测试用例的名称,必须以“test_”开头。否则即便定义了测试用例也不会被执行。

      • 用例的执行顺序与定义的先后顺序无关,而是根据用例名称来排序执行的。如test_1会比test_2先执行。

    • 所有测试用例的运行

      • 在main代码块内调用unittest.main()

        

     1 import unittest
     2 
     3 
     4 class TestDemo(unittest.TestCase):
     5 
     6     def setUp(self) -> None:
     7         print('执行每个测试用例前的准备工作')
     8 
     9     def tearDown(self) -> None:
    10         print('执行完每个测试用例后的收尾工作')
    11 
    12     def test_1(self):
    13         print('测试用例1')
    14 
    15     def test_2(self):
    16         print('测试用例2')
    17 
    18     def a(self):
    19         print('不按命名规则的测试用例')
    20 
    21 
    22 if __name__ == '__main__':
    23     unittest.main()
    24 
    25     
    26     
    27 执行结果:
    28 
    29 执行每个测试用例前的准备工作
    30 测试用例1
    31 执行完每个测试用例后的收尾工作
    32 执行每个测试用例前的准备工作
    33 测试用例2
    34 执行完每个测试用例后的收尾工作
    35 ..
    36 ----------------------------------------------------------------------
    37 Ran 2 tests in 0.000s
    38 
    39 OK

    数据驱动测试

    • ddt模块的使用

      • ddt模块的data装饰器可以给测试用例传入数据

      • 需要使用ddt模块给测试用例传入数据,需要先使用ddt装饰器给对应的测试用例的类进行装饰

     1 import unittest
     2 from ddt import ddt, data
     3 
     4 
     5 @ddt
     6 class TestDemo(unittest.TestCase):
     7 
     8     def setUp(self) -> None:
     9         print('执行每个测试用例前的准备工作')
    10 
    11     def tearDown(self) -> None:
    12         print('执行完每个测试用例后的收尾工作')
    13 
    14     @data('我是传入的数据')
    15     def test_1(self, data):
    16         print(data)
    17 
    18 
    19 if __name__ == '__main__':
    20     unittest.main()
    • 注意点

      • 如果data装饰器传入多条数据,表示该用例会被执行多少次,每次使用不同的数据来测试

       1 import unittest
       2 from ddt import ddt, data
       3 
       4 
       5 @ddt
       6 class TestDemo(unittest.TestCase):
       7 
       8     def setUp(self) -> None:
       9         print('执行每个测试用例前的准备工作')
      10 
      11     def tearDown(self) -> None:
      12         print('执行完每个测试用例后的收尾工作')
      13 
      14     @data('我是传入的数据1', '我是传入的数据2')
      15     def test_1(self, data1):
      16         print(data1)
      17 
      18 
      19 if __name__ == '__main__':
      20     unittest.main()
      21 
      22 执行结果:
      23 执行每个测试用例前的准备工作
      24 我是传入的数据1
      25 执行完每个测试用例后的收尾工作
      26 执行每个测试用例前的准备工作
      27 我是传入的数据2
      28 执行完每个测试用例后的收尾工作
      29 ..
      30 ----------------------------------------------------------------------
      31 Ran 2 tests in 0.000s
      32 
      33 OK
      • 如果测试用例的函数需要接收多个参数,需要将每一组数据放在列表中传入

        • 需要特别注意的是,即便使用列表将多个参数对应的数据传入测试用例。整个列表还是会被当做是一个整体默认传给第一个参数,此时使用*[]语法是错误的,这样列表中的元素会被拆分成一个个独立的元素,作为每一次测试使用的测试数据。

        • 此时需要使用ddt模块中的例外一个装饰器—unpack。它会负责将列表内的元素对应的传给参数。

       1 import unittest
       2 from ddt import ddt, data, unpack
       3 
       4 
       5 @ddt
       6 class TestDemo(unittest.TestCase):
       7 
       8     def setUp(self) -> None:
       9         print('执行每个测试用例前的准备工作')
      10 
      11     def tearDown(self) -> None:
      12         print('执行完每个测试用例后的收尾工作')
      13 
      14     @data(['我是传入的数据1', '我是传入的数据2'], ['第二组用例的数据1', '第二组用例的数据2'])
      15     @unpack
      16     def test_1(self, data1, data2):
      17         print(data1)
      18         print(data2)
      19 
      20 
      21 if __name__ == '__main__':
      22     unittest.main()
      23 
      24     
      25 执行结果:
      26 执行每个测试用例前的准备工作
      27 我是传入的数据1
      28 我是传入的数据2
      29 执行完每个测试用例后的收尾工作
      30 执行每个测试用例前的准备工作
      31 第二组用例的数据1
      32 第二组用例的数据2
      33 执行完每个测试用例后的收尾工作
      34 ..
      35 ----------------------------------------------------------------------
      36 Ran 2 tests in 0.000s
      37 
      38 OK

    断言

    • 断言就是一个测试用例预期结果与实际结果的对比(实际结果是否与预期符合)

    • unittest的常用的一些断言:

      # 判断 a == b,msg表示错误提示信息
      self.assertEqual(a, b, msg='a不等于b')
      
      # 判断 a != b
      self.assertNotEqual(a, b)
      
      # 判断 bool(x) is True
      self.assertTrue(x)
      
      # 判断 bool(x) is False
      self.assertFalse(x)
      
      # 判断 a is b
      self.assertIs(a, b)
      
      # 判断 a is not b
      self.assertIsNot(a, b)
      
      # 判断 x is None
      self.assertIsNone(x)
      
      # 判断 x is not None
      self.assertIsNotNone(x)
      
      # 判断 a in b
      self.assertIn(a, b)
      
      # 判断 a not in b
      self.assertNotIn(a, b)
      
      # 判断 isinstance(a, b)
      self.assertIsInstance(a, b)
      
      # 判断 not isinstance(a, b)
      self.assertNotIsInstance(a, b)
       

    Skip操作

    • 将某些暂时不需要执行的测试用例跳过

      1 @unittest.skip('无条件跳过')
      2 def test_1(self, data1, data2):
      3     print(data1)
      4     print(data2)
      5     self.assertEqual(1, 2, msg='1不等于2')
    • 给指定测试用例加上skip装饰器,即可无条件跳过该测试用例

    • 有条件限制的跳过测试用例:

      • skipUnless装饰器

        • 当条件为False时会跳过当前测试用例

        1 @unittest.skipUnless(1 > 2, '条件为假跳过')
        2 def test_2(self):
        3     print(111)
      • skipIf装饰器

        • 当条件为True时会跳过当前测试用例

        1 @unittest.skipIf(2 > 1, '条件为真时跳过')
        2 def test_3(self):
        3     print(222)
    • 测试用例断言为假时(与预期结果不符)标记该测试用例

      • expectedFailure装饰器

        1 @unittest.expectedFailure
        2 def test_4(self):
        3     self.assertEqual(1, 2, '1不等于2')
        4     
        5 该测试用例被标记为:
        6 expected failures=1
        7 注意:
        8     和skip不同,skip是根据条件或者无条件跳过不执行测试用例
        9     expectedFailure是执行完测试用例后,将与预期不符的测试用例标记出来

      使用了该装饰器的测试用例,断言结果必须是错误的。不允许成功

      否则会出现以下错误:

      Test should not succeed since it's marked with @unittest.expectedFailure

    测试套件和测试运行器

    • 测试套件

      • 将想要执行的测试用例加入到一个测试套件内,然后通过运行器执行测试套件内的测试用例,即可实现执行部分测试用例。

      • 测试套件不能与测试用例在一个文件内,否则即使使用测试运行器运行测试套件,还是会执行所有用例。

         1 import unittest
         2 from test import TestDemo
         3 
         4 # 实例化测试套件
         5 suite = unittest.TestSuite()
         6 # 添加测试用例
         7 suite.addTest(TestDemo('test_1'))
         8 suite.addTest(TestDemo('test_3'))
         9 
        10 # 实例化测试运行器
        11 runner = unittest.TextTestRunner()
        12 runner.run(suite)
    • 往测试套件内添加测试用例的多种方式:

      • 上述例子中,直接通过指定测试用例类中的测试用例方法名,将测试用例添加至套件内。

        • 上述例子添加用例的方式可优化:

          1 cases = [TestDemo('test_1'), TestDemo('test_3')]
          2 suite.addTests(cases)
      • 通过正则匹配查询,将指定路径下所有匹配成功的测试用例全都加入测试套件内

        1 discover = unittest.defaultTestLoader.discover(start_dir='./', pattern='test*.py')
        2 3 # 实例化测试运行器
        4 runner = unittest.TextTestRunner()
        5 runner.run(discover)
        6 7 # 此时运行器执行的是从‘./’路径下,也就是当前路径下所有与‘test*.py’相匹配的测试用例文件内的测试用例的集合。
      • 直接将指定测试用例类对象中的所有测试用例添加至套件内

        1 suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestDemo))
      • 将上述方式改为通过类名称方式将所有用例添加至套件内

        1 suite.addTests(unittest.TestLoader().loadTestsFromName('test.TestDemo'))
        2 3 # 注意类名称必须通过指定包/模块加‘.’的形式
    • 测试运行器

      • 主要用于执行测试套件

     

    HTMLTestRunner

    • 用于生成测试报告

      • 报告内只记录通过的用例和失败的用例,没有跳过的用例。

    • HTMLTestRunner配置

      • 下载地址:http://tungwaiyip.info/software/HTMLTestRunner.html

      • 由于下载的HTMLTestRunner.py文件是基于Python2的,若适用于Python3则进行如下修改:

        • 94行, import StringIO

        • 539行,self.outputBuffer = StringIO.StringIO()

        • 631行,print >>sys.stderr, ' Time Elapsed: %s' % (self.stopTime-self.startTime)

        • 642行,if not rmap.has_key(cls):

        • 766行,uo = o.decode('latin-1')

        • 772行,ue = e.decode('latin-1')

      • 将下载的文件保存到:PythonXXLib目录下。

    • 基本用法     

     1 import unittest
     2 from HTMLTestRunner import HTMLTestRunner
     3 from test import TestDemo
     4  5 # 实例化测试套件
     6 suite = unittest.TestSuite()
     7  8 # 生成测试报告
     9 report_name = '测试报告名称.html'
    10 report_title = '测试报告标题'
    11 report_desc = '测试报告描述'
    12 report_path = './'
    13 report_file = report_path + report_name
    14 15 with open(report_file, 'wb') as report:
    16     suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestDemo))
    17     runner = HTMLTestRunner(stream=report, title=report_title, description=report_desc)
    18     runner.run(suite)
  • 相关阅读:
    python之字典
    Python包管理工具
    【转】Python实现修改Windows CMD命令行输出颜色(完全解析)
    进程池中传递实例方法问题
    HTML协议详解
    【转】python数据格式化之pprint
    【转】Python装饰器与面向切面编程
    【转】TCP/IP报文格式
    python之线程学习
    python之面向对象
  • 原文地址:https://www.cnblogs.com/yamx/p/13602484.html
Copyright © 2011-2022 走看看