Python 中 Mock 到底该怎么玩?一篇文章告诉你(超全)

1. 前言

微服务架构下,由于各类服务开发进度的不一致,导致联调工作经常会存在不确定性,进而导致项目延期

在实际工作中,为了保证项目进度,我们经常需要针对部分未完成模块及不稳定模块采用 Mock 方式,以验证已开发完的模块

本篇文章将介绍 Python 实现 Mock 的几种常见方式

2. Mock 介绍

Mock 测试:在测试验证过程中,对于那些尚未完成或不稳定的对象,用一个虚拟对象来替代,以便测试的测试方法

因此,这个虚拟的对象是 Mock 对象,Mock 对象是真实对象在调试期间的代替品

它的优势包含:

  • 前、后端并行开发

  • 模拟无法访问的资源

  • 隔离系统,避免脏数据干扰测试结果

3.1 mock

在 Python 3.3 之前使用 mock,需要先安装依赖

# 安装mock依赖
pip3 install mock

项目地址:

https://github.com/testing-cabal/mock

假设 Product 类中有 2 个方法

  • get_product_status_by_id

  • buy_product

其中,get_product_status_by_id 方法还没有实现;buy_product 方法依赖于 get_product_status_by_id 方法的返回值

# product_impl.py

class Product(object):

def __init__(self):
        pass

def get_product_status_by_id(self, product_id):
        """
        通过商品id获取产品信息(Mock)
        :return:
        """
        # 待实现查询数据库的业务逻辑
        pass

def buy_product(self, product_id):
        """
        购买产品(真实逻辑)
        :return:
        """
        # 产品信息
        # {"id":1,"name":"苹果","num":23}
        product = self.get_product_status_by_id(product_id)

if product.get("num") >= 1:
            result = {"status": 0, "msg": "购买成功!"}
        else:
            result = {"status": 1, "msg": "购买失败,库存不足!"}

return result

Mock 的步骤如下:

  • 导入使用 mock 中的 patch 方法

  • 作为测试方法的装饰器,对 get_product_status_by_id 方法进行 Mock,方法参数为 Mock 对象

  • 测试方法中,对该 Mock 对象设置一个返回值

  • 调用并断言

from mock import patch
from mock_.product_impl import Product

@patch('mock_.product_impl.Product.get_product_status_by_id')
def test_succuse(mock_get_product_status_by_id):
    # Mock方法,指定一个返回值
    mock_get_product_status_by_id.return_value = {"id": 1, "name": "苹果", "num": 23}

product = Product()

assert product.buy_product(1).get("status") == 0

需要注意的是,Mock 此方法的时候,必须制定该方法的完整路径

使用 @patch.object 同样能完成 Mock,不同的是,@patch.object 包含 2 个参数

第一个参数为该方法所在的类;第二个参数为方法名

from mock import patch

from mock_.product_impl import Product

# Mock一个方法
# @patch.object:对象、方法名
@patch.object(Product, 'get_product_status_by_id')
def test_succuse(mock_get_product_status_by_id):
    # Mock方法,指定一个返回值
    mock_get_product_status_by_id.return_value = {"id": 1, "name": "苹果", "num": 23}

product = Product()

assert product.buy_product(1).get("status") == 0

3.2 unittest.mock

Python 3.3 之后,mock 作为标准库,已经内置到 unittest 中了

还是以 3.1 的场景为例,使用 unittest 编写一个测试用例

Mock 步骤如下:

  • 导入 unittest 框架中的 mock 文件

  • 实例化 Product 对象

  • mock.Mock(return_value=*) 方法

    对 get_product_status_by_id 方法进行 Mock

  • 调用并断言

import unittest
from unittest import mock

from unittest_mock.product_impl import Product

class TestProduct(unittest.TestCase):

def test_success(self):
        # 成功结果
        mock_success_value = {"id": 1, "name": "苹果", "num": 23}

product = Product()

product.get_product_status_by_id = mock.Mock(return_value=mock_success_value)

# 调用实际函数
        assert product.buy_product(1).get("status") == 0

if __name__ == "__main__":
    unittest.main()

3.3 pytest.mock

相比 unittest,pytest 由于强大的插件支持,用户群体可能更大!

如果项目本身使用的框架是 pytest,则 Mock 更建议使用 pytest-mock 这个插件

# pytest依赖
pip3 install pytest

Mock 步骤如下:

  • 使用 pytest 编写测试方法,参数为 mocker

  • 实例化 Product 对象

  • 使用 mocker.patch() 方法对 get_product_status_by_id 方法进行 Mock,并设置返回值

  • 调用并断言

import pytest

from pytest_mock_.product_impl import Product

def test_buy_product_success(mocker):
    """
    购买成功Mock
    :param mocker:
    :return:
    """
    # 实例化一个产品对象
    product = Product()

# 对Product中的方法的返回值进行Mock
    mock_value = {"id": 1, "name": "苹果", "num": 23}

# Mock方法
    # 注意:需要指定方法的完整路径
    # mocker.patch 的第一个参数必须是模拟对象的具体路径,第二个参数用来指定返回值
    product.get_product_status_by_id = mocker.patch("product_impl.Product.get_product_status_by_id",
                                                    return_value=mock_value)

# 调用购买产品的方法
    result = product.buy_product(1)

assert result.get("status") == 0

需要注意的是,mocker.patch 方法第一个参数必须是 Mock 对象的完整路径

4. 最后

文中对 Python 中常见的 Mock 方案进行了讲解,实际应用中,建议根据项目实际情况进行选型

我已经将文中完整源码文件传到后台,关注公众号,后台回复「 pmock 」即可获得

如果你觉得文章还不错,请大家 点赞、分享、留言 下,因为这将是我持续输出更多优质文章的最强动力!

留言送书
本周赠书:《从零学 Selenium 自动化

PS:中奖名单将在交流群公布,可以扫描下方二维码,备注【交流群】,加入技术交流群!
(0)

相关推荐

  • python笔记23-unittest单元测试之mock

    什么是mock unittest.mock是一个用于在Python中进行单元测试的库,Mock翻译过来就是模拟的意思,顾名思义这个库的主要功能是模拟一些东西. 它的主要功能是使用mock对象替代掉指定 ...

  • 做好单元测试,你不能不会的Mock

    为了隔离其他函数.类或者接口,在做测试的过程中,尤其是单元测试的过程中,Mock 是少不了的技术了.今天这篇文章就给大家介绍一下 Python 的Mock 技术 Mock 介绍Mock 是允许用模拟对 ...

  • 我被学妹白嫖了,python自动化测试经验全部传授,没想到最后竟然......

    先来一张学妹美照: 事情是这样的:学妹刚入门的软件测试,薪水只有5000元左右,想转自动测试或者初入测试岗位,要拿到年薪15-25W,问我应该怎样学习 作为一个入行8年的测试老鸟,这不就到我装逼的时候 ...

  • python笔记24-unittest单元测试之mock.patch

    前言 上一篇python笔记23-unittest单元测试之mock对mock已经有初步的认识, 本篇继续介绍mock里面另一种实现方式,patch装饰器的使用,patch() 作为函数装饰器,为您创 ...

  • 古建筑砖地面到底怎么排,一篇文章告诉你

    获取文物保护工程专业人员资格考试最新信息 小测试 Q1·  传统建筑的台基组成部分有哪几项? Q2·  传统建筑的台基形制有哪几种? 小提示:可以参考上一期推送哦 答案在文末 题目只是针对大纲内容的知 ...

  • 高大上的蒙氏教育到底是什么?一篇文章告诉你

    导语 一份针对高层管理人员的研究表明,89%的被测人员都具有85分以上的纪律性和高度的独立自主能力.一位来自国内某知名在线票务公司的人士透露,其在单项测试的部分,纪律性.自由.创造力分项指标均到达85 ...

  • 一篇文章告诉你,书法中的章法,到底有多重要?

    哈喽,各位同学大家好啊! 由今天来分享一些关于章法方面的二三事. 什么是章法? 这个问题看起来似乎很简单,但要写一个比较完整的回答,其实还是有一些困难的. 原因在于,书法作品中的章法之说,尤其是软笔书 ...

  • 说说Python中PEP8到底是什么?

    公众号新增加了一个栏目,就是每天给大家解答一道Python常见的面试题,反正每天不贪多,一天一题,正好合适,只希望这个面试栏目,给那些正在准备面试的同学,提供一点点帮助! 小猿会从最基础的面试题开始, ...

  • 一篇文章告诉你:边款到底该怎么玩?

    常听人说"善书者不择笔",高人自有高招,如同武侠小说里头武功深者摘片树叶就能当暗器,甚至隔山打牛连兵器都不需要了.记得<吉舟印话>中,吉舟石开先生言其一支山马笔,用得顺 ...

  • 贵阳地铁游攻略:一篇文章告诉你,如何通过地铁玩转贵阳

    目前为止,贵阳已经开通了地铁1号线和2号线,而3号线和s1号线正在建设之中.通过地铁,贵阳城内的许多交通枢纽.景点都联系在了一起.许多游客初到贵阳,并不知道乘坐地铁到哪里可以进行中转,也不知道到哪里可 ...

  • “吃素”到底好不好?一篇文章带你看穿素食的真相

    有人说, 人类进化了几十万年才爬上食物链的顶端, 可不是为了吃草. 然而,现在吃素的人越来越多了. 素食日渐风靡. 过去吃素可能是为了信仰,宗教,为了不杀生. 如今吃素是为了健康. 那么吃素有什么好处 ...

  • 2021年买手机,骁龙870与骁龙888到底哪个好?一篇文章读懂

    很奇怪,为什么总有人说"2021年买手机别选骁龙888"? 持有这种观点的人,理由无非涉及到:888芯片太"火龙",打游戏巨烫,与其花大钱争一个吉祥数字,不如选 ...

  • 都江堰不只是历史书上的水利工程,一篇文章告诉你可以怎么玩!

    那天跟朋友说起都江堰,朋友接过话来:"都江堰不就是古代那个水利工程吗?"我恍了下神,其实都江堰不仅仅只是水利工程,同时也还是一座城市. 这跟另一个地名有着异曲同工之处,我们都知道黄 ...