zoukankan      html  css  js  c++  java
  • python接口自动化测试

    mock简介

    mock作用

    解决依赖问题,达到解耦作用

    当我们测试某个目标接口(模块)时,该接口依赖其他接口,当被依赖的接口未开发完成时,可以用mock模拟被依赖接口,完成目标接口的测试

    模拟复杂业务的接口

    当我们测试某个目标接口(模块),该接口依赖一个非常复杂的接口时,可以用mock来模拟这个复杂的业务接口;也解决接口依赖一样的原理

    单元测试

    如果某个接口(模块)未开发完成时,又需要编写测试用例,则可以通过mock模拟该接口(模块)进行测试

    前后端联调

    前端开发的页面需要根据后端返回的不同状态码展示不同的页面,当后端接口未开发完成时,也可通过mock来模拟后端接口返回自己想要的数据

    mock类解读

    class Mock(spec=None,side_effect=None,return_value=DEFFAULT,name=None) 

    • secp:定义mock对象的属性值,可以是列表,字符串,甚至一个对象或者实例 
    • side_effect:可以用来抛出异常或者动态改变返回值,它必须是一个iterator(列表),它会覆盖return_value
    • return_value:定义mock方法的返回值,它可以是一个值,可以是一个对象(如果存在side_effect参数那这个就没有用,也就是不能同时用)
    • name:作为mock对象的一个标识,在print时可以看到

    mock实际使用

    一个未开发完成的功能如何测试?

     1 def add(self, a, b):
     2     """两个数相加"""
     3     pass
     4 
     5 
     6 class TestSub(unittest.TestCase):
     7     """测试两个数相加用例"""
     8 
     9     def test_sub(self):
    10         # 创建一个mock对象 return_value代表mock一个数据
    11         mock_add = mock.Mock(return_value=15)
    12         # 将mock对象赋予给被测函数
    13         add = mock_add
    14         # 调用被测函数
    15         result = add(5, 5)
    16         # 断言实际结果和预期结果
    17         self.assertEqual(result, 15)

    一个完成开发的功能如何测试?

    class SubClass(object):
        def add(self, a, b):
            """两个数相加"""
            return a + b
    
    
    class TestSub(unittest.TestCase):
        """测试两个数相加用例"""
    
    
        def test_add2(self):
            # 初始化被测函数类实例
            sub = SubClass()
            # 创建一个mock对象 return_value代表mock一个数据
            # 传递side_effect关键字参数, 会覆盖return_value参数值, 使用真实的add方法测试
            sub.add = Mock(return_value=15, side_effect=sub.add)
            # 调用被测函数
            result = sub.add(5, 5)
            # 断言实际结果和预期结果
            self.assertEqual(result, 10)

    side_effect:这里给的参数值是sub.add相当于add方法的地址,当我们调用add方法时就会调用真实的add方法

    简单理解成:传递了side_effect参数且值为被测函数地址时,mock不会起作用;两者不可共存

    另外,side_effect接受的是一个可迭代序列,当传递多个值时,每次调用mock时会返回不同的值;如下

     1 mock_obj = mock.Mock(side_effect= [1,2,3])
     2 print(mock_obj())
     3 print(mock_obj())
     4 print(mock_obj())
     5 print(mock_obj())
     6 
     7 # 输出
     8 Traceback (most recent call last):
     9 1
    10   File "D:/MyThreading/mymock.py", line 37, in <module>
    11 2
    12     print(mock_obj())
    13 3
    14   File "C:Python36libunittestmock.py", line 939, in __call__
    15     return _mock_self._mock_call(*args, **kwargs)
    16   File "C:Python36libunittestmock.py", line 998, in _mock_call
    17     result = next(effect)
    18 StopIteration

    存在依赖关系的功能如何测试?

     1 # 支付类
     2 class Payment:
     3 
     4     def requestOutofSystem(self, card_num, amount):
     5         '''
     6         请求第三方外部支付接口,并返回响应码
     7         :param card_num: 卡号
     8         :param amount: 支付金额
     9         :return: 返回状态码,200 代表支付成功,500 代表支付异常失败
    10         '''
    11         # 第三方支付接口请求地址(故意写错)
    12         url = "http://third.payment.pay/"
    13         # 请求参数
    14         data = {"card_num": card_num, "amount": amount}
    15         response = requests.post(url, data=data)
    16         # 返回状态码
    17         return response.status_code
    18 
    19     def doPay(self, user_id, card_num, amount):
    20         '''
    21         支付
    22         :param userId: 用户ID
    23         :param card_num: 卡号
    24         :param amount: 支付金额
    25         :return:
    26         '''
    27         try:
    28             # 调用第三方支付接口请求进行真实扣款
    29             resp = self.requestOutofSystem(card_num, amount)
    30             print('调用第三方支付接口返回结果:', resp)
    31         except TimeoutError:
    32             # 如果超时就重新调用一次
    33             print('重试一次')
    34             resp = self.requestOutofSystem(card_num, amount)
    35 
    36         if resp == 200:
    37             # 返回第三方支付成功,则进行系统里面的扣款并记录支付记录等操作
    38             print("{0}支付{1}成功!!!进行扣款并记录支付记录".format(user_id, amount))
    39             return 'success'
    40 
    41         elif resp == 500:
    42             # 返回第三方支付失败,则不进行扣款
    43             print("{0}支付{1}失败!!不进行扣款!!!".format(user_id, amount))
    44             return 'fail'
    45 
    46 # 单元测试类
    47 class payTest(unittest.TestCase):
    48 
    49     def test_pay_success(self):
    50         pay = Payment()
    51         # 模拟第三方支付接口返回200
    52         pay.requestOutofSystem = mock.Mock(return_value=200)
    53         resp = pay.doPay(user_id=1, card_num='12345678', amount=100)
    54         self.assertEqual('success', resp)
    55 
    56     def test_pay_fail(self):
    57         pay = Payment()
    58         # 模拟第三方支付接口返回500
    59         pay.requestOutofSystem = mock.Mock(return_value=500)
    60         resp = pay.doPay(user_id=1, card_num='12345678', amount=100)
    61         self.assertEqual('fail', resp)
    62 
    63     def test_pay_time_success(self):
    64         pay = Payment()
    65         # 模拟第三方支付接口首次支付超时,重试第二次成功
    66         pay.requestOutofSystem = mock.Mock(side_effect=[TimeoutError, 200])
    67         resp = pay.doPay(user_id=1, card_num='12345678', amount=100)
    68         self.assertEqual('success', resp)
    69 
    70     def test_pay_time_fail(self):
    71         pay = Payment()
    72         # 模拟第三方支付接口首次支付超时,重试第二次失败
    73         pay.requestOutofSystem = mock.Mock(side_effect=[TimeoutError, 500])
    74         resp = pay.doPay(user_id=1, card_num='12345678', amount=100)
    75         self.assertEqual('fail', resp)

    也许有小伙伴会问,第三方支付都不能用,我们的测试结果是否是有效的呢?

    通常在测试一个模块的时候,是可以认为其他模块的功能是正常的,只针对目标模块进行测试是没有任何问题的,所以说测试结果也是正确的

    mock装饰器

    一共两种格式

    1.  @patch('module名字.方法名') 
    2.  @patch.object(类名, '方法名') 
     1 # 装饰类演示
     2 from mock import Mock, patch
     3 
     4 
     5 # 单独的相乘函数
     6 def multiple(a, b):
     7     return a * b
     8 
     9 
    10 # 单独的捕获Exception函数
    11 def is_error():
    12     try:
    13         os.mkdir("11")
    14         return False
    15     except Exception as e:
    16         return True
    17 
    18 
    19 # 计算类,包含add方法
    20 class calculator(object):
    21     def add(self, a, b):
    22         return a + b
    23 
    24 
    25 # 装饰类演示 - 单元测试类
    26 class TestProducer(unittest.TestCase):
    27 
    28     # case执行前
    29     def setUp(self):
    30         self.calculator = calculator()
    31 
    32     # mock一个函数,注意也要指定module
    33     @patch('mock_learn.multiple')
    34     def test_multiple(self, mock_multiple):
    35         mock_multiple.return_value = 3
    36         self.assertEqual(multiple(8, 14), 3)
    37 
    38     # mock一个类对象的方法
    39     @patch.object(calculator, 'add')
    40     def test_add(self, mock_add):
    41         mock_add.return_value = 3
    42         self.assertEqual(self.calculator.add(8, 14), 3)
    43 
    44     # mock调用方法返回多个不同的值
    45     @patch.object(calculator, 'add')
    46     def test_effect(self, mock_add):
    47         mock_add.side_effect = [1, 2, 3]
    48         self.assertEqual(self.calculator.add(8, 14), 1)
    49         self.assertEqual(self.calculator.add(8, 14), 2)
    50         self.assertEqual(self.calculator.add(8, 14), 3)
    51 
    52     # mock的函数抛出Exception
    53     @patch('os.mkdir')
    54     def test_exception(self, mkdir):
    55         mkdir.side_effect = Exception
    56         self.assertEqual(is_error(), True)
    57 
    58     # mock多个函数,注意函数调用顺序
    59     @patch.object(calculator, 'add')
    60     @patch('mock_learn.multiple')
    61     def test_more(self, mock_multiple, mock_add):
    62         mock_add.return_value = 1
    63         mock_multiple.return_value = 4
    64         self.assertEqual(self.calculator.add(3, 3), 1)
    65         self.assertEqual(multiple(3, 3), 4)
  • 相关阅读:
    Linux系统组成和获取命令帮助2
    Linux系统组成和获取命令帮助1
    3P修饰
    PHP-简单生成唯一数
    Go语言实现APPID登录
    磁盘满了,却看不到是谁占用的
    Redis安装、配置和卸载
    docker 加入域名
    Docker安装
    Swoft+Docker
  • 原文地址:https://www.cnblogs.com/poloyy/p/12233507.html
Copyright © 2011-2022 走看看