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+yLog.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 pytestfrom 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=109result=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, unstubwhen(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,Mockimport 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=109result=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=xself.y=ydef first_add(self):return self.x+self.ydef 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=608result=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,不同参数,返回的值不同

pytest-mock的使用相关推荐

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

    1. 前言 微服务架构下,由于各类服务开发进度的不一致,导致联调工作经常会存在不确定性,进而导致项目延期 在实际工作中,为了保证项目进度,我们经常需要针对部分未完成模块及不稳定模块采用 Mock 方式 ...

  2. setuptools清华源_setuptools与pip的依赖关系解决方案之间的差异

    我最近开始用SetupTools打包我的第一个项目,并且大部分都取得了成功.setuptools与pip的依赖关系解决方案之间的差异 不幸的是,我遇到了一个令人困惑的情况 - 我的项目依赖于PyPI上 ...

  3. utittest和pytest中mock的使用详细介绍

    Mock是Python中一个用于支持单元测试的库,它的主要功能是使用mock对象替代掉指定的Python对象,以达到模拟对象的行为. python3.3 以前,mock是第三方库,需要安装之后才能使用 ...

  4. python自动化测试框架pytest.pdf_Python自动化测试框架

    随着技术的进步和自动化技术的出现,市面上出现了一些自动化测试框架.只需要进行一些适用性和效率参数的调整,这些自动化测试框架就能够开箱即用,大大节省了开发时间.而且由于这些框架被广泛使用,他们具有很好的 ...

  5. java junit mock_使用Mockito进行Java的Mock测试

    测试替身 dummy用于传递,不会真正使用,例如用于填充的方法的参数列表. Fake有简单实现,但通常被简化,比如在内存数据库,而不是真正的数据库中使用. Stub是接口或类中部分实现,测试时使用其实 ...

  6. pytest之Monkeypatching(猴子补丁)

    猴子补丁(monkey patching)理解 在运行时动态修改模块.类或函数,通常是添加功能或修正缺陷. 猴子补丁在代码运行时(内存中)发挥作用,不会修改源码,因此只对当前运行的程序实例有效. 因为 ...

  7. 「高效程序员的修炼」快速上手python主流测试框架pytest以及单元测试编写

    如果对你有帮助,就点个赞吧~ 本文主要介绍如果编写Python的单元测试,包括如何使用断言,如何考虑测试哪些情况,如何避免外部依赖对测试的影响,如果用数据驱动的方式简化重复测试的编写等等等等 文章目录 ...

  8. 【pytest】(十)fixture参数化-巧用params和ids优雅的创建测试数据

    我们都知道参数化. 比如我要测试一个查询接口/test/get_goods_list,这个接口可以查询到商品的信息. 在请求中,我可以根据请参数goods_status的不同传值,可以查询到对应状态的 ...

  9. pytest+yaml设计接口自动化框架过程记录(一步一步记录如何设计,完结撒花),源码提供,视频教程

    pytest+yaml设计接口自动化框架过程记录 第三代框架使用教程,该框架比现在这个完善了很多 框架简介 框架运行演示和功能介绍视频 pytest+yaml框架环境配置和使用教程 0.去年也写了一个 ...

  10. 学习版pytest内核测试平台开发万字长文入门篇

    前言 2021年,测试平台如雨后春笋般冒了出来,我就是其中一员,写了一款pytest内核测试平台,在公司落地.分享出来后,有同学觉得挺不错,希望能开源,本着"公司代码不要传到网上去,以免引起 ...

最新文章

  1. 腾讯云 cloudbase 云开发使用笔记
  2. mysql 5.7 api 中文_mysql5.7怎么解决中文
  3. 脑洞大开!油画渲染的新算法 Paint Transformer!ICCV2021 Oral!
  4. 进栈顺序为abcd则出栈顺序为_进栈顺序为a、b、c、d,则出栈顺序可以为?
  5. 类支付宝微信密码输入框
  6. 结合工作经历推荐新手编程语言
  7. 2 HTTP和HTTPS
  8. numpy 库使用说明
  9. CentOS下安装JDK7
  10. 联想昭阳K22-80机器关闭或开启触摸板方法
  11. Qt:十六进制字符串和十六进制互转
  12. DIY面试题 for AI产品经理 | “智能音箱半夜诡异笑声”的原因分析及建议方案
  13. python习题20190130
  14. 泛在传感器网络(Ubiquitous Sensor Network; USN)
  15. 不得不佩服下自己:关于正反双面打印的问题分析
  16. 日语学习之——五十音图
  17. 【无法打开登录所请求的数据库, 登录失败。】解决方案
  18. jlink怎么调试linux程序_【转】ubuntu linux下openocd + gdb-insight 用Jlink调试arm程序
  19. Linux的进程状态
  20. Revit API 进阶之隐藏dll讲解.

热门文章

  1. Jenkins 定时备份插件 ThinBackup
  2. fastDFS 分布式文件系统新增加storage
  3. VR全景的发展,VR全景加盟-VR全景智慧城市
  4. 慢即是快,少即是多!
  5. 慕课软件工程(第十七章.习题5.1)
  6. 取消CATIA启动时自动创建的Product或Part
  7. ZigBee_协议栈简介
  8. Maximum Tape Utilization Ratio
  9. .NET用户注册邮箱验证
  10. vue 统计中英文字符串长度_Ant Design Vue 添加区分中英文的长度校验功能