ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Mock这个词在英语中有

2026/8/19 8:47:30 拓冰建站 浏览量
Mock这个词在英语中有 Mock是什么这个英语单词Mock有着模拟的意思, 所以据此能够猜测这个库的主要功能是去模拟某些事物。确切说道, Mock是一个用于施以单元测试支持的库, 它的主要功能是借助mock对象去替换掉指定对象, 以此达成模拟对象行为的目的。简而言之, mock库应用于如下这般的场景:假设你所开发的项目名为a, 此项目里含有一个模块b, 而模块b之中存在一个函数c, 即a.b.c, 该函数在运行时要调用并发送请求至特定的服务器, 以此获取一个JSON返回值, 随后依据这个返回值来进行处理。要是要为a.b.c函数编写一个单元测试, 那该如何去做呢?有个办法较为简单, 所要做的是搭建起一个用于测试的服务器, 于单元测试之际, 使得a.b.c函数与这个测试服务器展开交互。然而, 这般做法存在着两个问题:搭建测试服务器, 有可能是特别不容易去搭建成的又或者搭建起来的效率呢是非常低的。你所搭建的那个测试服务器, 或许是没办法把所有可能出现的值给返回回来的, 要不然就是得投入大量的工作才能够走到实现这个目的这一步的。在没有测试服务器的情形下, 要怎样去开展上面所提及那种状况的单元测试呢, Mock模块便是答案所在。上面已说过的, mock模块能够对对象予以替换。而我们假定a.b.c的代码是如下这般:import requests def c(url): resp requests.get(url) # further process with resp要是运用mock模块, 便能达成如此效果: 拿一个mock对象去替换上面的.get函数, 则在执行函数c之际, c调用.get的返回值可由我们的mock对象来定, 而无需服务器介入。浅显来讲, 就是我们借助一个mock对象去替换c函数与服务器交互的进程。想必你定然好奇此功能怎样实现, 这是mock模块内部的实现机制, 不在本文探讨范畴。本文着重探讨, 怎样运用mock模块, 来化解上面提及的, 那种单元测试场景。Mock的安装和导入于3.3之前的版本里头, 得额外安装mock模块才行, 此可借由pip命令进行安装:$ sudo pip install mock然后在代码中就可以直接进来import mock起始于3.3, mock模块已然并入标准库, 其被命名为.mock, 能够直接拿来运用:from unittest import mockMock对象基本用法最为重要的概念存在于mock模块当中, 它便是Mock对象, Mock对象属于mock模块里一个类的实例表现, 该类实例可供用来把其他对象进行替换, 以此达成模拟的成效, Mock类的定义陈列如下:class Mock(specNone, side_effectNone, return_valueDEFAULT, wrapsNone, nameNone, spec_setNone, **kwargs)仅是在此给出这个定义, 目的是去说明, Mock对象着实就是个类罢了, 当然, 其内部的实现是极为巧妙的, 有兴趣的话, 可以去看mock模块的代码。Mock对象的一般用法是这样的去寻得你打算替换的那个对象, 此对象能够是一个类, 又或者是一个函数, 还可能是一个类实例。接着对 Mock 类进行实例化从而得到一个 mock 对象, 进而设定这个 mock 对象的行径, 诸如被调用之际返回何种值, 被访问成员之时返回何种值等等。运用这个 mock 对象去置换掉我们想要替换掉的对象, 也就是步骤 1 里已然确定的对象。随后便可着手撰写测试代码, 在这个时候我们能够确保我们替换掉的对象于测试用例执行的进程当中行为以及我们预先设定好的相一致。举例来讲: 存在一个简易的客户端实现, 其目的在于去访问一个URL, 若访问表现为正常的状况, 那么就应当返回状态码200, 要是不正常的话就要返回状态码404。首先, 实施如下这般我们的客户端代码:#!/usr/bin/env python # -*- coding: utf-8 -*- import requests def send_request(url): r requests.get(url) return r.status_code def visit_ustack(): return send_request(http://www.ustack.com)通过外部模块调用(), 从而前往访问的官网。接下来, 我们于单元测试里, 运用mock对象, 分别针对访问正常以及访问不正常的状况展开测试。#!/usr/bin/env python # -*- coding: utf-8 -*- import unittest import mock import client class TestClient(unittest.TestCase): def test_success_request(self): success_send mock.Mock(return_value200) client.send_request success_send self.assertEqual(client.visit_ustack(), 200) def test_fail_request(self): fail_send mock.Mock(return_value404) client.send_request fail_send self.assertEqual(client.visit_ustack(), 404)所要寻找的需替换的对象是: 此函数是我们要进行测试的, 进而我们要将这个函数替换掉。通过实例化Mock类从而得到一个mock对象, 还要对这个mock对象的行为予以设置。于成功测试情况里, 我们把mock对象的返回值设为字符串“200”, 在失败测试情形中, 我们将mock对象的返回值设定为字符串404。利用这个mock对象去替换掉我们意图替换的对象。我们成功实现了替换.着手编写测试代码。我们执行调用.(), 并且期望它所返回的值与我们预先设定的保持一致。就上面提及的那个而言, 此乃运用 mock 对象的基本步骤。于上述所列举的事例当中, 我们将我们自行编写出的模块范围内的对象予以了替换, 事实上, 同样能够对标准库以及第三方模块范畴内的对象进行替换, 其办法是相同的: 先是来到里面, 接着把指定状况下的对象替换掉便达成所愿了。稍微高级点的用法class Mock的参数最开始所说的, 是mock对象最为基础的使用方式, 接下来要看一看mock对象稍微更具进阶性质的使用方法, 并非是特别高深的那种, 要是想了解最为完备、最为高级的, 直接去查看mock的文档就行, 稍后会给出。过来先瞧一瞧Mock这么个类的参数, 在所看到的于上方那般的类的定义里, 我方明白它存在好些数量的参数, 于此处讲述相对最为主要些许的特定几个:其他的参数请参考官方文档。mock对象的自动创建在访问一个不存在于mock对象里的属性之时, mock会自动去建立一个子mock对象, 并且将正在被访问的属性指向它, 此功能对于达成多级属性的mock来讲是颇为便利的。client mock.Mock() client.v2_client.get.return_value 200在这个特定的时候, 你获取到了一个经过mock处理的实例, 当你调用这个该实例展现而出的.get()方法时, 所得到的返回值呈现为200。往上头的示例里头同样能够瞧见, 去指定mock对象之时, 还能够运用属性赋值的方式。对方法调用进行检查用于检查mock对象是否被调用过的方法存在, 用于检查该对象被调用时参数情况的若干方法也存在, 用于检查其被调用次数等的相关情况部分方法同样存在。实现针对mock对象这些功能的达成能够通过调用其相关方法来进行, 要特别明晰具体的细节事项, 可去查看mock的文档。在此处, 我们给出一个示例。仍是运用上面的代码, 此次我们要查验, 在()函数调用()函数之际, 传出的参数类别是否恰当。我们能够依照下面这般动用mock对象。class TestClient(unittest.TestCase): def test_call_send_request_with_right_arguments(self): client.send_request mock.Mock() client.visit_ustack() self.assertEqual(client.send_request.called, True) call_args client.send_request.call_args self.assertIsInstance(call_args[0][0], str)Mock对象的属性表示该mock对象是否被调用过。用来呈现该mock对象被调用情况的tuple, 此tuple的每一个成员都是一个mock.call对象。mock.call这个对象所代表的是针对mock对象的一次调用, 其自身的内容是一个tuple, 此tuple含有两个元素, 其中第一个元素是在调用mock对象当时的位置参数*args, 第二个元素是调用mock对象时运用的关键字参数**。现在来分析下上面的用例我们要检查的项目有两个()进行了调用, 此次调用所采用的参数是一个字符串patch, 以及patch。知晓了mock对象后, 我们来看两个利于测试的函数: 一个是patch、另一个是patch.。这两个函数都会给出一个mock内部的类实例,该类是class。给出的这个类实例既能够当作函数的装饰器, 又能够当作类的装饰器, 还能够当作上下文管理器。运用patch或者patch. 的意图是为了把控mock的范围, 意思是在一个指定函数的范围内, 或者一个特定类的范围内, 或者with语句的范围之内mock掉某个对象。我们看个代码例子即可class TestClient(unittest.TestCase): def test_success_request(self): status_code 200 success_send mock.Mock(return_valuestatus_code) with mock.patch(client.send_request, success_send): from client import visit_ustack self.assertEqual(visit_ustack(), status_code) def test_fail_request(self): status_code 404 fail_send mock.Mock(return_valuestatus_code) with mock.patch(client.send_request, fail_send): from client import visit_ustack self.assertEqual(visit_ustack(), status_code)这个测试类, 与我们方才所写的首个测试类相同, 它涵盖两个测试, 只是此次并非呈现创建一个mock对象并予以替换, 而是运用了patch函数, 此函数作为上下文管理器来使用。“patch.”所呈现的效果, 与“patch”是相同的, 只是在使用方式上存在些许差异。比如说, 就如同上面所提及的那个例子, 要是将其换成“patch.”, 那么情况会是这样的:def test_fail_request(self): status_code 404 fail_send mock.Mock(return_valuestatus_code) with mock.patch.object(client, send_request, fail_send): from client import visit_ustack self.assertEqual(visit_ustack(), status_code)就是替换掉一个对象的指定名称的属性用法和类似。如何学习使用mock你想必特纳闷, 这篇文章难道不是教着怎么去使用mock的呀? , 并不是这样的, 我发觉自己于学习mock之时碰到的主要难题在于并不明晰mock能够做些什么, 并非mock对象究竟存有哪些函数。所以撰写这篇文章的主要意图是为了阐明mock能够做些什么。如若你已明晰mock所能达成之事后, 那该以怎样的方式去学习进而掌握mock呢? 最为恰当的办法便是去查看翻阅官方文档, 并且于自身的单元测试里予以运用。最终, 去学习mock技能, 你理应能体会到一种掌控的愉悦之感, 也就是你能够尽情享受操控外部服务的那种乐趣。在你察觉到这种愉悦之感之际, 你的mock想必就已然达到熟练运用的程度了。官方文档 2.7mock还未加入标准库。3.4mock已经加入了标准库。