【Python自动化测试】mock模块基本使用介绍

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:\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_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装饰器

一共两种格式

@patch('module名字.方法名')

@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)

下面是配套学习资料,对于做【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!

相关推荐
16月6日-晴6 分钟前
Java面向对象进阶—多态
java·开发语言
冯汉栩34 分钟前
Swift Control RollingCountdownView(动画倒计时)
开发语言·ios·swift
lisanmengmeng37 分钟前
搭建elk环境并接入frostmourne,实现监控报警效果(五)
开发语言·elk·日志·日志监控
Groundwork Explorer1 小时前
W5500 网卡编程初始化与使用指南
python·单片机
oh,huoyuyan1 小时前
JS 动态网页抓不到?试试火车采集器网页抓取工具
开发语言·javascript·ecmascript
风流 少年1 小时前
hutool
java·服务器·开发语言
逸Y 仙X2 小时前
MCP(模型控制协议)完全指南:从核心概念到实战开发
python·大模型·llm·ai编程·mcp
一木 之林2 小时前
四、STL容器与数据结构
开发语言·数据结构·c++
QX_hao2 小时前
【Go】--Cobra-cli的用法
开发语言·后端·golang
艾醒(AiXing-w)2 小时前
LangChain 1.0 入门(三):稳定性双核心——重试机制+速率限速器参数详解与实战
开发语言·langchain·php