pytest-mock的使用

2023-11-15

mock介绍

当一个功能依赖另一个功能时,而这个功能还没有完善,需要使用mock来模拟依赖的返回
mock主要有以下几个库:

  1. unittest.mock:python内置的用于mock的库,有Mock,MagicMock,path等类可以使用
  2. pytest-mock: 第三方插件库
  3. monkeypatch:pytest内置的fixture,也可以提供mock功能
  4. mockito:第三方库

where to mock

要使用mock,首先得明白mock的原理,在哪个地方mock
以unittest.mock来举例:
使用Mock()或者MagicMock()会生成一个Mock或者MagicMock对象,当调用时,就会返回mock的值。如下:

from unittest.mock import Mock,MagicMock
f=Mock(return_value=34)
print(f()) #34
print(f) #<Mock id='140295868166688'>

Mock(return_value=34),初始化生成一个Mock对象,这个对象在内存中有一个地址,地址是以140开头的
f=Mock(return_value=34),将这个地址赋值给了f,此时,f的地址就是Mock id=‘140295868166688’
当调用f()时就会返回Mock对象的值
所以猜测,Mock是通过将Mock对象的地址赋值给要调用的函数或者方法的地址,改变返回值
所以问题是:在哪里mock?
在方法调用的模块或者查找的模块mock
The key is to patch out SomeClass where it is used (or where it is looked up).
比如:

#mian1.py:
def add(x,y):
    result=x+y
    Log.info("result:{}".format(result))
    return result
#mian4.py中调用add,但是导入的方式不同,先看from XXX import XXX
from LearnPytest.task.main1 import add
def my_add_four(x,y):
    result=add(x,y)
    return result
#在test_mymock_one.py中测试my_add_four函数,以下两种mock方式
def test_my_mock():
    main4.add=Mock(return_value=567)
    result=my_add_four(4,5)
    print(result)

def test_my_mock_one():
    main1.add=Mock(return_value=900)
    result = my_add_four(4, 5)
    print(result)

if __name__ == '__main__':
    pytest.main(["-v","-s","test_mymock_one.py::test_my_mock"])

test_my_mock这种方式的mock起作用,先分析这种mock方式:
首先生成了一个mock对象,return_value在mock调用时才会返回
在这里插入图片描述
运行完main4.add=Mock(return_value=567),这里的main4.add已经被替换为mock对象了,需要运行到main4.py时看add的地址
在这里插入图片描述
代码运行到main4.py中查看,add已经被替换为mock对象了,当代码里调用add时,mock对象就会被调用,所以mock才会起作用
在这里插入图片描述
test_my_mock_one
执行完成main1.add=Mock(return_value=900),发现main1的add被替换成了mock对象,
在这里插入图片描述
继续运行到main4.py,查看add的地址,这里的add的地址不是mock对象的地址,所以mock不起作用
在这里插入图片描述
使用另一种import XXX来导入模块时,需要在查到方法的地方mock

#mian5.py,通过import来调用add方法
import LearnPytest.task.main1
def my_add_five(x,y):
    result=LearnPytest.task.main1.add(x,y)
    return result
#在test_mymock_two.py中测试my_add_five方法
import pytest

from LearnPytest.task.main5 import my_add_five
from LearnPytest.task import main5
from unittest.mock import Mock
from LearnPytest.task import main1
def test_mymock_one():  #mock不起作用
    main5.add=Mock(return_value=800)
    result=my_add_five(4,7)
    print(result)
def test_mymock_two():  #mock起作用
    main1.add=Mock(return_value=809)
    result=my_add_five(4,5)
    print(result)

if __name__ == '__main__':
    pytest.main(["-v","-s","test_mymock_two.py::test_mymock_two"])
    

unittest.mock使用介绍

(1)Mock类的定义
class unittest.mock.Mock(spec=None, side_effect=None, return_value=DEFAULT, wraps=None, name=None, spec_set=None, unsafe=False, **kwargs)¶
其中,return_value是当mock被调用时返回一个值
side_effect:This can either be a function to be called when the mock is called, an iterable or an exception (class or instance) to be raised.
side_effect的值可以是一个function,或者一个可迭代或者一个异常
当mock对象被调用时,传入的function会被以相同的参数调用
Mock还可以替换对象
MagicMock是Mock的子类
Mock objects are callable. The call will return the value set as the return_value attribute. The default return value is a new Mock object; it is created the first time the return value is accessed (either explicitly or by calling the Mock) - but it is stored and the same one returned each time.
Mock对象是可调用的,但是存储起来,所以mock一个方法后,后续再调用这个方法,mock仍在存在,如果想解掉这个mock,需要使用patch装饰器
(2)patch
patch是一个装饰器,只在函数范围内来mock对象,函数结束后,自动解mock,即使测试中遇到异常
The patch decorators are used for patching objects only within the scope of the function they decorate. They automatically handle the unpatching for you, even if exceptions are raised. All of these functions can also be used in with statements or as class decorators.
patch的定义:
unittest.mock.patch(target, new=DEFAULT, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs)¶
target:是需要mock的类(被mock的类),是一个string,类似“package.module.ClassName"
当参数new忽略时,要创建的mock对象,作为被patch装饰的的function的一个额外的参数传入
patch会自动创建一个MagicMock的对象
如下是一个如何mock方法的例子:

#my_new_add.py里调用了add方法
def my_add(x,y):
    result=add(x,y)
    return result
#test_three.py里测试my_add方法,并且对add方法进行mock
@patch("src.my_add.add",)
def test_mock_one(mock_function):
    mock_function.return_value=109
    result=my_add(4,5)
    print(result)

在这里插入图片描述
由上图可以看出,patch创建了一个名字为mock_function的MagicMock的对象
这个MagicMock对象如何和src.my_add.add进行绑定,使用target
在这里插入图片描述

monkeypatch的使用介绍

monkeypatch是pytest内置的一个fixture
monkeypath能够安全的设置或者删除属性,字典的item以及环境变量
所有的设置在function或者fixture完成后会解绑
monkeypatch提供的方法有:
monkeypatch.setattr(obj, name, value, raising=True)
monkeypatch.setattr(“somemodule.obj.name”, value, raising=True)
monkeypatch.delattr(obj, name, raising=True)
monkeypatch.setitem(mapping, name, value)
monkeypatch.delitem(obj, name, raising=True)
monkeypatch.setenv(name, value, prepend=None)
monkeypatch.delenv(name, raising=True)
monkeypatch.syspath_prepend(path)
monkeypatch.chdir(path)
monkeypatch的使用场景有:
(1)改变一个函数或者一个类的属性,通过使用monkeypatch.setattr或者monkeypatch.delattr方法
(2)改变一个字典的值,通过monkeypatch.setitem和monkeypatch.delitem
(3)改变环境变量的值,通过monkeypatch.setenv和monkeypatch.delenv

如下代码:

def mockreturn(x,y):
    return 808
def test_mock_two(monkeypatch):
    monkeypatch.setattr('src.my_add.add',mockreturn)
    result=my_add(6,7)
    print(result)

当执行到monkeypatch.setattr时,monkeypatch的属性setattr被赋值了,function的地方是add的地址
在这里插入图片描述
当执行到my_add中时,查看add函数,发现它的地址变为mockreturn的地址,返回了我们需要的值
在这里插入图片描述
monkeypatch的官网:
https://docs.pytest.org/en/latest/how-to/monkeypatch.html

mockito

mockito是一个第三方库
官方文档:https://mockito-python.readthedocs.io/en/latest/#

from mockito import when, mock, unstub

when(os.path).exists('/foo').thenReturn(True)

# or:
import requests  # the famous library
# you actually want to return a Response-like obj, we'll fake it
response = mock({'status_code': 200, 'text': 'Ok'})
when(requests).get(...).thenReturn(response)

# use it
requests.get('http://google.com/')

# clean up
unstub()

mockito主要用作同一个方法或者函数,入参不同时,返回的值不同
使用mockito,之后要记得unstub,unstub可以放在teardown中

mock的具体使用场景

如何mock一个函数
from unittest.mock import patch,Mock

import src
from src.my_add import my_add
import pytest


#使用patch来mock
@patch("src.my_add.add",)
def test_mock_one(mock_function):
    mock_function.return_value=109
    result=my_add(4,5)
    print(result)

#使用monkeypatch
def mockreturn(x,y):
    return 808
def test_mock_two(monkeypatch):
    monkeypatch.setattr('src.my_add.add',mockreturn)
    result=my_add(6,7)
    print(result)

#使用Mock或者MagicMock
def test_mock_three():
    src.my_add.add=Mock(return_value=404)
    result=my_add(5,6)
    print(result)
如何mock一个类中的方法
#定义一个类
class MyAdd():
    def __init__(self,x,y):
        self.x=x
        self.y=y
    def first_add(self):
        return self.x+self.y
    def second_fuction(self):
        return self.x-self.y
#在my_add.py中调用这个类的一个方法
def my_first_function(x,y):
    my_add=MyAdd(x,y)
    result=my_add.first_add(x,y)
    return result
#在test_four.py中测试my_first_function,需要mock first_add方法
from src.my_add import my_first_function
import pytest
from unittest.mock import Mock,MagicMock,patch

#使用patch来mock
@patch("src.my_add.MyAdd")
def test_mock_one(mock_class):
    a=mock_class.return_value  #返回这个mock的实例
    a.first_add.return_value=608
    result=my_first_function(4,5)
    print(result)

#使用with patch
class MockClass(MagicMock):
    first_add=MagicMock(return_value=809)
def test_mock_two():
    with patch("src.my_add.MyAdd",MockClass) as mock:
        result=my_first_function(6,7)
        print(result)
#使用monkeypatch
def mockreturn(*args):
    return 708
def test_mock_three(monkeypatch):
    monkeypatch.setattr("src.my_add.MyAdd.first_add",mockreturn)
    result = my_first_function(6, 7)
    print(result)
if __name__ == '__main__':
    pytest.main(["-v","-s","test_four.py::test_mock_one"])
如何mock,不同参数,返回的值不同
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

pytest-mock的使用 的相关文章

  • Kivy - 文本换行工作错误

    我正在尝试在 Kivy 1 8 0 应用程序中换行文本 当没有太多文字时 一切正常 但如果文本很长并且窗口不是很大 它只是剪切文本 这是示例代码 vbox BoxLayout orientation vertical size hint y
  • Python 2.7 将比特币私钥转换为 WIF 私钥

    作为一名编码新手 我刚刚完成了教程 教程是这样的 https www youtube com watch v tX XokHf nI https www youtube com watch v tX XokHf nI 我想用 1 个易于阅读
  • 将 numpy 数组写入文本文件的速度

    我需要将一个非常 高 的两列数组写入文本文件 而且速度非常慢 我发现如果我将数组改造成更宽的数组 写入速度会快得多 例如 import time import numpy as np dataMat1 np random rand 1000
  • 使用 Django Rest 保存 Base64ImageField 类型会将其保存为原始图像。如何将其转换为普通图像

    我的模型中有 5 个图像字段 imageS imageS imageS imageS 和 imageE 我正在尝试按以下方式保存图像 图像的类型Base64ImageField images imageA imageB imageC ima
  • Tweepy StreamListener 到 CSV

    我是 python 新手 我正在尝试开发一个应用程序 使用 Tweepy 和 Streaming API 从 Twitter 检索数据并将数据转换为 CSV 文件 问题是此代码不会创建输出 CSV 文件 也许是因为我应该将代码设置为在实现例
  • 了解 Python 中的酸洗

    我最近接到一项作业 需要以腌制形式放置一本字典 其中每个键引用一个列表 唯一的问题是我不知道腌制形式是什么 谁能给我指出一些好的资源的正确方向来帮助我学习这个概念 pickle 模块实现了一个基本但强大的算法 用于序列化和反序列化 Pyth
  • 在 macOS 中通过 Python 访问进程的压缩 RAM(顶部的 CMPRS)的方法?

    我试图弄清楚如何从 Python 访问任何给定进程占用的实际 RAM 量 我发现 psutil Process PID memory info rss 工作得很好 直到操作系统决定开始压缩某些进程的 RAM 然后 所有的 memory in
  • 当单词以“|”分隔时如何读取文件(埃因霍温)?

    在Python中 我有一个文件 其中的单词由 例如 city state zipcode 我的文件阅读器无法区分单词 另外 我希望我的文件阅读器从第 2 行而不是第 1 行开始 如何让我的文件阅读器分隔单词 import os import
  • 登录网站并使用 python 请求下载文件

    我有一个带有 HTML 表单的网站 登录后 它会将我带到 start php 站点 然后将我重定向到overview php 我想从该服务器下载文件 当我单击 ZIP 文件的下载链接时 链接后面的地址是 getimage php path
  • 可以用 Django 制作移动应用程序吗?

    我想知道我是否可以在我的网站上使用 Django 代码 并以某种方式在移动应用程序 Flutter 等框架中使用它 那么是否可以使用我现在拥有的 Django 后端并在移动应用程序中使用它 所以就像models views etc 是的 有
  • Apache Spark 中的高效字符串匹配

    我使用 OCR 工具从屏幕截图中提取文本 每个大约 1 5 句话 然而 当手动验证提取的文本时 我注意到时不时会出现一些错误 鉴于文本 你好 我真的很喜欢 Spark 我注意到 1 像 I 和 l 这样的字母被 替换 2 表情符号未被正确提
  • PySide6.1 与 matplotlib 3.4 不兼容

    当我只安装PySide6时 GUI程序运行良好 但是一旦我安装了matplotlib及其依赖包 包括pyqt5 则GUI程序将无法运行并输出以下错误消息 This application failed to start because no
  • 如何使用 Django 项目设置 SQLite?

    我已阅读 Django 文档 仅供参考 https docs djangoproject com en 1 3 intro tutorial01 https docs djangoproject com en 1 3 intro tutor
  • Pandas style.bar 颜色基于条件?

    如何渲染其中一列的 Pandas dfstyle bar color属性是根据某些条件计算的 Example df style bar subset before after color ff781c vmin 0 0 vmax 1 0 而
  • 解析根元素内元素之间的 XML 文本

    我正在尝试用 Python 解析 XML 以下是 XML 结构的示例 a aaaa1 b bbbb b aaaa2 a
  • 无法在 python 3.8 上将带有 webapp 的 python 部署到 azure

    我正在尝试使用部署一个测试项目Flask使用以下方法将框架迁移到 Azure 云中Azure CLI https learn microsoft com en us azure app service containers quicksta
  • 如何使用 Keras ImageDataGenerator 预测单个图像?

    我已经训练 CNN 对图像进行 3 类分类 在训练模型时 我使用 keras 的 ImageDataGenerator 类对图像应用预处理功能并重新缩放它 现在我的网络在测试集上训练得非常准确 但我不知道如何在单图像预测上应用预处理功能 如
  • Python 通过从现有 csv 文件中过滤选定的行来写入新的 csv 文件

    只是一个问题 我试图将 csv 文件中的选定行写入新的 csv 文件 但出现错误 我试图读取的 test csv 文件是这样的 两列 2013 9 1 2013 10 2 2013 11 3 2013 12 4 2014 1 5 2014
  • Python:高精度time.sleep

    你能告诉我如何在 Win32 和 Linux 上的 Python 2 6 中获得高精度睡眠函数吗 您可以在中使用浮点数sleep http docs python org library time html time sleep 该参数可以
  • 缓存 Flask-登录 user_loader

    我有这个 login manager user loader def load user id None return User query get id 在我引入 Flask Principal 之前它运行得很好 identity loa

随机推荐

  • 卷积的本质及物理意义(全面理解卷积)

    卷积的本质及物理意义 提示 对卷积的理解分为三部分讲解1 信号的角度2 数学家的理解 外行 3 与多项式的关系 1 来源 卷积其实就是为冲击函数诞生的 冲击函数 是狄拉克为了解决一些瞬间作用的物理现象而提出的符号 古人曰 说一堆大道理不如举
  • ChatGPT指令大全(英文版)

    ChatGPT指令大全 英文版 前言 Act as a Linux Terminal Act as an English Translator and Improver Act as position Interviewer Act as
  • WebApi 登录身份验证

    前言 Web 用户的身份验证 及页面操作权限验证是B S系统的基础功能 一个功能复杂的业务应用系统 通过角色授权来控制用户访问 本文通过Form认证 Mvc的Controller基类及Action的权限验证来实现Web系统登录 Mvc前端权
  • 将代码提交到Github代码托管平台

    本篇文章呢 阿Q将为大家讲解如何将自己的代码上传到github这个第三方代码托管平台 并更新代码 阿Q本次就以上一个Dialog的Demo为例 将其上传到github 要想上传代码到github 大家需要做一下准备工作 首先要将Git GU
  • Softmax的实现

    详解 https zhuanlan zhihu com p 25723112
  • 带icon的输入框el-input 给icon图标绑定点击事件

    element官网传送门 带icon的输入框有两种方式 选择第二种 添加点击事件
  • opengl API glCheckFramebufferStatus详解

    Name glCheckFramebufferStatus glCheckNamedFramebufferStatus check the completeness status of a framebuffer C Specificati
  • SQL解析Json字段

    MySQL支持原生JSON类型 使用JSON数据类型相较于将JSON格式的字符串存储在String型中的优势有 存储时会自动验证JSON文本 可以优化存储格式 存储在JSON型中的JSON文本会被转换成一个支持快速读取的文档元素 这样在使用
  • python基础一:计算机要点学习

    一 计算机的基本概念 1 计算机是什么 计算机是一种用于高速运算的电子机器 手机 电脑 计算器等 特点 数值计算 逻辑计算 对事物进行逻辑分析并进行判断得到的计算结果 存储记忆功能 计算机是能够按照程序运行 自动 高速处理数据的现代化电子设
  • postman几种常见的请求方式

    1 get请求直接拼URL形式 对于http接口 有get和post两种请求方式 当接口说明中未明确post中入参必须是json串时 均可用url方式请求 参数既可以写到URL中 也可写到参数列表中 都一样 请求时候都是拼URL 2 pos
  • [深入理解Android卷二 全文-第六章]深入理解ActivityManagerService

    由于 深入理解Android 卷一 和 深入理解Android卷二 不再出版 而知识的传播不应该因为纸质媒介的问题而中断 所以我将在CSDN博客中全文转发这两本书的全部内容 第6章 深入理解ActivityManagerService 本章
  • 魏副业而战:付费是最快的成长途径

    我是魏哥 与其在家躺平 不如魏副业而战 在生活中 为了提高孩子学习成绩 你会给他报辅导班 在工作中 为了提升工作效率 为了晋升 你会报课 考证书 但很少人为了自己的成长而主动付费学习 这是为什么呢 因为他没认识到付费的价值 魏哥之前也是喜欢
  • 互联网+商业模式

    大数据商业模式 10种商业模式 一 人工智能 数据 物体 智能 人工智能是数据变现的最好方式 但是目前是2B的智能买单意愿更强 GDP 20 数据是为人服务的 人接触最多的是物体 数据的智慧将延伸人的五官 拓展人的四肢 这些都依赖硬件 数据
  • 【数据结构与算法】链表OJ练习题

    作者 一只大喵咪1201 专栏 数据结构与算法 格言 你只管努力 剩下的交给时间 习题 1 移除链表元素 2 反转链表 3 链表的中间结点 4 链表中倒数第k个结点 5 合并两个有序链表 6 链表分割 7 链表的回文结构 8 相交链表 9
  • Java:求一个数组中连续子元素最大和

    public class TestArray public static int FindGreatestSumOfSubArray int array if array length 0 array null return 0 int c
  • log4j:WARN No appenders could be found for logger 解决办法

    使用log4j时不起作用 每次执行完出现以下提示 log4j WARN No appenders could be found for logger org apache ibatis logging LogFactory log4j WA
  • Linux性能分析之perf(1)基础知识总结

    Linux 09 之perf 1 基础知识总结 Author Onceday Date 2023年1月31日 漫漫长路 才刚刚开始 参考文档 Tutorial Perf Wiki kernel org linux性能分析工具专题 perf
  • FPGA-VGA协议实践

    前言 概述 VGA Video Graphics Array 视频图形阵列 是一种视频传输标准 具有分辨率高 显示速度快 颜色丰富等优点 不支持音频传输 硬件设备 FPGA开发板DE2 115 软件环境 软件环境 Quartus 一 VGA
  • one-hot Embedding 理论知识详解 + 代码实操 (为学习笔记模式,同时附完整代码)【独热向量编码】

    目 标 使用one hot Embedding 处理数据库查询语句 使其变成向量模式 以下为个人学习笔记和学习过程中用到的完整代码 环 境 腾讯云服务器 Linux系统 具体环境会在代码段前进行标注 目录 一 one hot 理论基础 二
  • pytest-mock的使用

    mock介绍 当一个功能依赖另一个功能时 而这个功能还没有完善 需要使用mock来模拟依赖的返回 mock主要有以下几个库 unittest mock python内置的用于mock的库 有Mock MagicMock path等类可以使用