Mock测试

Mock测试是一种在开发和测试过程中,通过模拟不易获取或复杂的依赖对象来简化测试的方法。它能解耦被测单元,提高测试效率,支持TDD模式,并允许模拟无法访问的资源。本文介绍了Mock测试的概念、原因、使用场景和优势,并通过Python的unittest.mock库展示了Mock测试的实践,包括支付接口的模拟测试。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. Mock测试

##1.1 什么是Mock测试
mock测试就是在测试过程中,对于某些不容易构造或者不容易获取的对象,用一个虚拟的对象来创建以便测试的测试方法。
换句话说,当一个接口依赖于另一个上游接口,恰好上有接口还不能提供服务,那么我们就需要模拟上游返回进行测试。

1.2 为什么要进行mock测试

Mock是为了解决不同的单元之间由于耦合而难以开发、测试的问题,所以,Mock可以出现在单元测试、集成测试、系统测试中。mock最大的功能就是把耦合分解。
例如:一个闹钟根据时间来进行提醒服务,如果过了下午5点钟就播放音频文件提醒大家下班了,如果我们要利用真实的对象来测试的话就只能苦苦等到下午五点,然后把耳朵放在音箱旁,我们应该利用mock对象来进行测试,这样我们就可以模拟控制时间了,而不用苦苦等待时钟转到下午5点钟了

1.3 Mock对象使用场景

1.需要将当前被测单元和其依赖模块独立分开,构造一个独立的测试环境,不关注被测单元的依赖对象,只关注被测单元的功能逻辑。
** 实例 **
被测试的代码中需要依赖第三方接口返回的值进行逻辑处理,可能因为网络或者其他环境因素,调用第三方接口经常会中断或者失败,无法对被测单元进行测试,这个时候就可以使用mock技术将被测单元和依赖模块独立开,以达到可测性。

2.被测单元以来的模块尚未开发完成,而被测单元需要依赖模块的返回值进行后续处理。
1)前后端项目中,后端接口开发完成之前,接口联调;
2)依赖的上游接口尚未开发完成,需要接口联调测试;
** 实例 **
service代码中,包含对Dao层的调用,但是Dao层还没有实现

3.被测单元以来的对象较难模拟或者不容易构造
** 实例 **
支付宝支付的异常情况有很多,但是模拟这种异常条件很复杂或者无法模拟。

1.4 Mock测试的优势

  1. 团队可以并行工作

有了Mock,前后端人员只需要定义好接口文档就可以开始并行工作,互不影响,只在最后的联调阶段往来密切;后端与后端之间如果有接口耦合,也同样能被Mock解决;测试过程中如果遇到依赖接口没有准备好,同样可以借助Mock;不会出现一个团队等待另一个团队的情况。这样的话,开发自测阶段就可以及早开展,从而发现缺陷的时机也提前了,有利于整个产品质量以及进度的保证。

2.开启TDD模式,即测试驱动开发

单元测试是TDD实现的基石,而TDD经常会碰到协同模块尚未开发完成的情况,但是有了mock,这些一切都不是问题。当接口定义好后,测试人员就可以创建一个Mock,把接口添加到自动化测试环境,提前创建测试。

3.可以模拟那些无法访问的资源

比如说,你需要调用一个“墙”外的资源来方便自己调试,就可以自己Mock一个。

4.隔离系统

假如我们需要调用一个post请求,为了获得某个响应,来看当前系统是否能正确处理返回的“响应”,但是这个post请求会造成数据库中数据的污染,那么就可以充分利用Mock,构造一个虚拟的post请求,我们给他指定返回就好了。

5.可以用来演示

假如我们需要创建一个演示程序,并且做了简单的UI,那么在完全没有开发后端服务的情况下,也可以进行演示。说到演示了,假如你已经做好了一个系统,并且需要给客户进行演示,但是里面有些真实数据并不想让用户看到,那么同样,你可以用Mock接口把这些敏感信息接口全部替换。

6.测试覆盖度

假如有一个接口,有100个不同类型的返回,我们需要测试它在不同返回下,系统是否能够正常响应,但是有些返回在正常情况下基本不会发生,比如,我们需要测试在当接口发生500错误的时候,app是否崩溃,别告诉我你一定要给服务端代码做些手脚让他返回500 。而使用mock,这一切就都好办了,想要什么返回就模拟什么返回,不用再担心我的测试覆盖度了!

2. Mock测试方式

1.python
实例1:简单使用

import requests
from unittest import mock

def request_my_blog():
    res = requests.get("http://www.my/blog")
    return res.status_code.encode("utf-8")


if __name__ == "__main__":
    request_my_blog = mock.Mock(return_value="这里是我的播客主页")
    print(request_my_blog())    #这里是我的播客主页

实例2:支付接口
支付类payment

import requests
from unittest import mock

class Payment:
    """
    定义第三方支付接口,并返回响应状态码
    """
    
    def authe(self, auth, card_num, amount):
        '''请求第三方接口,并返回状态码
            @param card_num:卡号
            @param amount:金额
            @param auth: 身份认证
            @author: ******
            @date: 20210423
            @return: 返回状态码,200:支付成功, 500:支付异常 ,401:鉴权失败
        '''
        url = "https://www.myzf.com"
        data = {"card_num": card_num, "amount": amount}
        headers = {"Authorzation":auth}
        res = requests.post(url, headers=headers, data=data)
        return res.status_code
    
    def pay(self, auth, card_num, amount):
        """
                    支付
        :param user_id: 用户id
        :param card_num: 卡号
        :param amount: 金额
        :return:
        """
        try:
            status_code = self.authe(auth, card_num, amount)
        except TimeoutError:
            status_code = self.authe(auth, card_num, amount)
            
        if status_code == 200:
            return {"result": True}
        elif status_code == 401:
            return {"result": False, "errorCode":4001, "errorMessage":"Authentication failed" }
        elif  status_code == 500:
            return {"result": False, "errorCode":5000, "errorMessage":"fail" }
             

测试类test_payment

import unittest
from f.payment import Payment
from unittest import mock

class PaymentTest(unittest.TestCase):
    """
    测试支付接口
    """
    def setUp(self):
        self.payment = Payment()
        
    def test_success(self):
        """
                    成功场景
        """
        self.payment.authe = mock.Mock(return_value=200)
        res = self.payment.pay(auth="test", card_num="123456", amount=1000)
        self.assertEqual(True, res["result"])
        
    def test_fail(self):
        """
                    失败场景
        """
        self.payment.authe = mock.Mock(return_value=500)
        res = self.payment.pay(auth="test", card_num="123456", amount=1000)
        self.assertEqual(False, res["result"])
        self.assertEqual(5000, res["errorCode"])
        self.assertEqual("fail", res["errorMessage"])
        
    def test_auth(self):
        """
                    鉴权失败
        """
        self.payment.authe = mock.Mock(return_value=401)
        res = self.payment.pay(auth="error", card_num="123456", amount=1000)
        self.assertEqual(False, res["result"])
        self.assertEqual(4001, res["errorCode"])
        self.assertEqual("Authentication failed", res["errorMessage"])

    #side_effect指定异常:
    
    def test_retry_success(self):
        """
                测试支付失败重试在成功
      side_effect 可以为序列类型 异常类型,对象
                如果为序列类型 每次调用mock对象,会依次将side effcet中的元素返回
        """
        self.payment.authe = mock.Mock(side_effect=[TimeoutError, 200])
        res = self.payment.pay(auth="test", card_num="1234444", amount=1000)
        self.assertTrue(res["result"])
        
        
if __name__=="__main__":
    unittest.main()
        

2.Fiddler
AutoResponder

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值