python接口自动化测试 - mock模块基本使用介绍
发布日期:2021-05-09 05:48:55 浏览次数:11 分类:博客文章

本文共 6681 字,大约阅读时间需要 22 分钟。

mock简介

  • py3已将mock集成到unittest库中
  • 为的就是更好的进行单元测试
  • 简单理解,模拟接口返回参数
  • 通俗易懂,直接修改接口返回参数的值
  • 官方文档:

 

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_add14         # 调用被测函数15         result = add(5, 5)16         # 断言实际结果和预期结果17         self.assertEqual(result, 15)

 

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

class SubClass(object):    def add(self, a, b):        """两个数相加"""        return a + bclass 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 110   File "D:/MyThreading/mymock.py", line 37, in 
11 212 print(mock_obj())13 314 File "C:\Python36\lib\unittest\mock.py", line 939, in __call__15 return _mock_self._mock_call(*args, **kwargs)16 File "C:\Python36\lib\unittest\mock.py", line 998, in _mock_call17 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_code18 19     def doPay(self, user_id, card_num, amount):20         '''21         支付22         :param userId: 用户ID23         :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         # 模拟第三方支付接口返回20052         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         # 模拟第三方支付接口返回50059         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 False15     except Exception as e:16         return True17 18 19 # 计算类,包含add方法20 class calculator(object):21     def add(self, a, b):22         return a + b23 24 25 # 装饰类演示 - 单元测试类26 class TestProducer(unittest.TestCase):27 28     # case执行前29     def setUp(self):30         self.calculator = calculator()31 32     # mock一个函数,注意也要指定module33     @patch('mock_learn.multiple')34     def test_multiple(self, mock_multiple):35         mock_multiple.return_value = 336         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 = 342         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的函数抛出Exception53     @patch('os.mkdir')54     def test_exception(self, mkdir):55         mkdir.side_effect = Exception56         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 = 163         mock_multiple.return_value = 464         self.assertEqual(self.calculator.add(3, 3), 1)65         self.assertEqual(multiple(3, 3), 4)

 

上一篇:python接口自动化测试 - unittest框架基本使用
下一篇:python接口自动化测试 - requests库的post请求进行文件下载

发表评论

最新留言

留言是一种美德,欢迎回访!
[***.207.175.100]2025年03月27日 11时05分03秒