pytest-mock的使用

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())
print(f)

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

比如:


def add(x,y):
    result=x+y
    Log.info("result:{}".format(result))
    return result

from LearnPytest.task.main1 import add
def my_add_four(x,y):
    result=add(x,y)
    return result

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调用时才会返回

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

import LearnPytest.task.main1
def my_add_five(x,y):
    result=LearnPytest.task.main1.add(x,y)
    return result

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():
    main5.add=Mock(return_value=800)
    result=my_add_five(4,7)
    print(result)
def test_mymock_two():
    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方法的例子:


def my_add(x,y):
    result=add(x,y)
    return result

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

pytest-mock的使用
由上图可以看出,patch创建了一个名字为mock_function的MagicMock的对象
这个MagicMock对象如何和src.my_add.add进行绑定,使用target
pytest-mock的使用

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的地址

pytest-mock的使用
当执行到my_add中时,查看add函数,发现它的地址变为mockreturn的地址,返回了我们需要的值
pytest-mock的使用
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)

import requests

response = mock({'status_code': 200, 'text': 'Ok'})
when(requests).get(...).thenReturn(response)

requests.get('http://google.com/')

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("src.my_add.add",)
def test_mock_one(mock_function):
    mock_function.return_value=109
    result=my_add(4,5)
    print(result)

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)

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

def my_first_function(x,y):
    my_add=MyAdd(x,y)
    result=my_add.first_add(x,y)
    return result

from src.my_add import my_first_function
import pytest
from unittest.mock import Mock,MagicMock,patch

@patch("src.my_add.MyAdd")
def test_mock_one(mock_class):
    a=mock_class.return_value
    a.first_add.return_value=608
    result=my_first_function(4,5)
    print(result)

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)

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,不同参数,返回的值不同

Original: https://blog.csdn.net/ljsykf/article/details/123041724
Author: 爱吃水饺的小京
Title: pytest-mock的使用

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/772240/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Python中的反射

    通过字符串映射或修改程序运行时的状态、属性、方法, 可以通过下面这4中方法 ”’ 使用getattr(object, name_str, default=None) 方法获取ob…

    Python 2023年6月3日
    085
  • 挑战 Google 搜索?OpenAI 发布最强 AI 对话系统 ChatGPT

    GPT-3 发布的两年后,我们没等来它的亲弟弟 GPT-4,而是在今天亲眼见证了 OpenAI 带来了一种全新的 AI 聊天机器人——ChatGPT,也可以称之为是 GPT-3 家…

    Python 2023年11月3日
    037
  • IQA图像质量评价 数据集介绍(LIVE、TID2013、CSIQ、LIVEC、KonIQ-10K)

    LIVE数据集 LIVE数据集是最大的可用注释图像质量数据集,由奥斯汀的德克萨斯大学图像和视频工程实验室于2006年建立,整个数据集的参考图片来源于互联网和摄影光盘中收集的29张高…

    Python 2023年10月26日
    062
  • Spark SQL(二):DataFrame APIs

    文章目录 一.主要DataFrame APIs 二.部分DataFrame APIs * 1.DataFrame.agg 2.DataFrame.alias 3.DataFrame…

    Python 2023年8月7日
    038
  • 【Python】控制结构,这个教程一般人我不给

    前言 还有多少人不会python的控制结构,在评论区告诉我,让我一个个点名提问。今天,就教会你python的控制结构… 分行与缩进 分行 •一条语句占用一行 过长的语句…

    Python 2023年5月24日
    062
  • MySQL5.7升级MySQL8.0完整卸载与安装并连接Navicat

    👑 博主简介:🥇 Java领域新星创作者🥇 阿里云开发者社区专家博主、星级博主、技术博主🤝 交流社区:BoBooY(优质编程学习笔记社区) 前言:本篇文章详细讲解了MySQL5.7…

    Python 2023年10月26日
    047
  • matplotlib 设置手动设置图例的位置大小

    如果你的英语好,可以看官网,官网写的很详细 matplotlib.legend — Matplotlib 3.6.2 documentation 图例背景\位置\大小 plt.le…

    Python 2023年9月3日
    068
  • 知识图谱补全(KGC)的常用方法

    构建知识图谱最为核心的一步就是知识抽取,但是知识抽取只能初步构建出图谱,要想得到内容比较准确的图数据库,还需要非常重要的一步,就是知识图谱的补全。 知识图谱补全主要有以下几种方法:…

    Python 2023年10月26日
    037
  • Linux系统如何查看已安装的python包 — 导出项目使用的依赖包

    1 Linux系统如何查看已安装的python包 Linux中查看安装的python包,那么可以使用pip list命令查看; pip是一个安装和管理Python包的工具,可以使用…

    Python 2023年8月3日
    073
  • 2021年挖掘猫眼专业版电影票房数据

    概述 自己看着玩玩,如有侵权,请联系我,立刻删除 爬取关键点1.猫眼票房字体动态加密,需要破解2.截止今日20210101-20211214,有350天左右,需要ip代理池,Pro…

    Python 2023年9月3日
    057
  • 【Python自动化Excel】Python与pandas字符串操作

    Python之所以能够成为流行的数据分析语言,有一部分原因在于其简洁易用的字符串处理能力。 Python的字符串对象封装了很多开箱即用的内置方法,处理单个字符串时十分方便;对于Ex…

    Python 2023年5月24日
    085
  • 精准用户画像!商城用户分群2.0!⛵

    💡 作者:韩信子@ShowMeAI📘 数据分析实战系列:https://www.showmeai.tech/tutorials/40📘 机器学习实战系列:https://www.s…

    Python 2023年10月29日
    052
  • Python将字符串转换成dataframe

    大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多…

    Python 2023年8月19日
    051
  • [密码学]:SM4

    [密码学]:SM4 SM4算法是我国商用密码标准,其前身是SMS4算法。SM4算法是一个分组加密算法,分组长度和密钥长度均128bit。SM4算法使用32轮的非线性迭代结构。SM4…

    Python 2023年8月2日
    069
  • 体验了一下火爆全球的 ChatGPT,我震惊了

    这几天,要说编程圈最热的话题,莫过于 OpenAI的 ChatGPT,写小说,写代码,找BUG,写论文,画漫画,谱曲……简直没有它干不了的事。 趁着下班时间…

    Python 2023年11月3日
    036
  • python基础

    1.数字类型(int float bool complex) 小结: 二进制1+1=10八进制7+1=10十六进制f+1=10 浮点只表示带有小数的数据,而小数点可以在相应的二进制…

    Python 2023年5月24日
    071
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球