什么是mock?

mock在翻译过来有模拟的意思。这里要介绍的mock是辅助单元测试的一个模块。它允许您用模拟对象替换您的系统的部分,并对它们已使用的方式进行断言。

在Python2.x 中 mock是一个单独模块,需要单独安装。

> pip install -U mock

在Python3.x中,mock已经被集成到了unittest单元测试框架中,所以,可以直接使用。

  可能你和我初次接触这个概念的时候会有这样的疑问:把要测的东西都模拟掉了还测试什么呢?

  但在,实际生产中的项目是非常复杂的,对其进行单元测试的时候,会遇到以下问题:

  • 接口的依赖
  • 外部接口调用
  • 测试环境非常复杂

  单元测试应该只针对当前单元进行测试, 所有的内部或外部的依赖应该是稳定的, 已经在别处进行测试过的.使用mock 就可以对外部依赖组件实现进行模拟并且替换掉, 从而使得单元测试将焦点只放在当前的单元功能。

简单的例子                                                        

我们先从最简单例子开始。

modular.py

#modular.py

class Count():

    def add(self):
pass

这里要实现一个Count计算类,add() 方法要实现两数相加。但,这个功能我还没有完成。这时就可以借助mock对其进行测试。

mock_demo01.py

from unittest import mock
import unittest from modular import Count # test Count class
class TestCount(unittest.TestCase): def test_add(self):
count = Count()
count.add = mock.Mock(return_value=13)
result = count.add(8,5)
self.assertEqual(result,13) if __name__ == '__main__':
unittest.main()

  count = Count()

  首先,调用被测试类Count() 。

  count.add = mock.Mock(return_value=7)

  通过Mock类模拟被调用的方法add()方法,return_value 定义add()方法的返回值。

  result = count.add(2,5)

  接下来,相当于在正常的调用add()方法,传两个参数2和5,然后会得到相加的结果7。然后,7的结果是我们在上一步就预先设定好的。

  self.assertEqual(result,7)

  最后,通过assertEqual()方法断言,返回的结果是否是预期的结果7。

  运行测试结果:

> python3 mock_demo01.py
.
----------------------------------------------------------------------
Ran 1 test in 0.000s OK

这样一个用例就在mock的帮助下编写完成,并且测试通过了。

完成功能测试                                                     

  再接下来完成module.py文件中add()方法。

#module.py

class Count():

    def add(self, a, b):
return a + b

  然后,修改测试用例:

from unittest import mock
import unittest
from module import Count class MockDemo(unittest.TestCase): def test_add(self):
count = Count()
count.add = mock.Mock(return_value=13, side_effect=count.add)
result = count.add(8, 8)
print(result)
count.add.assert_called_with(8, 8)
self.assertEqual(result, 16) if __name__ == '__main__':
unittest.main()

 count.add = mock.Mock(return_value=13, side_effect=count.add)

  side_effect参数和return_value是相反的。它给mock分配了可替换的结果,覆盖了return_value。简单的说,一个模拟工厂调用将返回side_effect值,而不是return_value。

  所以,设置side_effect参数为Count类add()方法,那么return_value的作用失效。

  result = count.add(8, 8)

  print(result)

  这次将会真正的调用add()方法,得到的返回值为16(8+8)。通过print打印结果。

  assert_called_with(8,8)

  检查mock方法是否获得了正确的参数。

解决测试依赖                                                     

   前面的例子,只为了让大家对mock有个初步的印象。再接来,我们看看如何mock方法的依赖。

  例如,我们要测试A模块,然后A模块依赖于B模块的调用。但是,由于B模块的改变,导致了A模块返回结果的改变,从而使A模块的测试用例失败。其实,对于A模块,以及A模块的用例来说,并没有变化,不应该失败才对。

  这个时候就是mock发挥作用的时候了。通过mock模拟掉影响A模块的部分(B模块)。至于mock掉的部分(B模块)应该由其它用例来测试。

# function.py
def add_and_multiply(x, y):
addition = x + y
multiple = multiply(x, y)
return (addition, multiple) def multiply(x, y):
return x * y

  然后,针对 add_and_multiply()函数编写测试用例。func_test.py

import unittest
import function class MyTestCase(unittest.TestCase): def test_add_and_multiply(self):
x = 3
y = 5
addition, multiple = function.add_and_multiply(x, y)
self.assertEqual(8, addition)
self.assertEqual(15, multiple) if __name__ == "__main__":
unittest.main()

运行结果:

>  python3 func_test.py
.
----------------------------------------------------------------------
Ran 1 test in 0.000s OK

  

  目前运行一切正确常,然而,add_and_multiply()函数依赖了multiply()函数的返回值。如果这个时候修改multiply()函数的代码。

……
def multiply(x, y):
return x * y + 3

  这个时候,multiply()函数返回的结果变成了x*y加3。

  再次运行测试:

>  python3 func_test.py
F
======================================================================
FAIL: test_add_and_multiply (__main__.MyTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "fun_test.py", line 19, in test_add_and_multiply
self.assertEqual(15, multiple)
AssertionError: 15 != 18 ----------------------------------------------------------------------
Ran 1 test in 0.000s FAILED (failures=1)

  测试用例运行失败了,然而,add_and_multiply()函数以及它的测试用例并没有做任何修改,罪魁祸首是multiply()函数引起的,我们应该把 multiply()函数mock掉。

import unittest
from unittest.mock import patch
import function class MyTestCase(unittest.TestCase): @patch("function.multiply")
def test_add_and_multiply2(self, mock_multiply):
x = 3
y = 5
mock_multiply.return_value = 15
addition, multiple = function.add_and_multiply(x, y)
mock_multiply.assert_called_once_with(3, 5) self.assertEqual(8, addition)
self.assertEqual(15, multiple) if __name__ == "__main__":
unittest.main()

  @patch("function.multiply")

  patch()装饰/上下文管理器可以很容易地模拟类或对象在模块测试。在测试过程中,您指定的对象将被替换为一个模拟(或其他对象),并在测试结束时还原。

  这里模拟function.py文件中multiply()函数。

  def test_add_and_multiply2(self, mock_multiply):

  在定义测试用例中,将mock的multiply()函数(对象)重命名为 mock_multiply对象。

  mock_multiply.return_value = 15

  设定mock_multiply对象的返回值为固定的15。

  ock_multiply.assert_called_once_with(3, 5)

  检查ock_multiply方法的参数是否正确。

  再次,运行测试用例,通过!

---------------------------------------------------

参考:

http://engineroom.trackmaven.com/blog/making-a-mockery-of-python/

python mock基本使用的更多相关文章

  1. Python mock

    在测试过程中,为了更好地展开单元测试,mock一些数据跟对象在所难免,下面讲一下python的mock的简单用法. 关于python mock,网上有很多资料,这里不会讲的特别深,但一定会是实用为主, ...

  2. 使用 Python Mock 类进行单元测试

    数据类型.模型或节点——这些都只是mock对象可承担的角色.但mock在单元测试中扮演一个什么角色呢? 有时,你需要为单元测试的初始设置准备一些“其他”的代码资源.但这些资源兴许会不可用,不稳定,或者 ...

  3. Python Mock的入门(转)

    原文:https://segmentfault.com/a/1190000002965620 Mock是什么 Mock这个词在英语中有模拟的这个意思,因此我们可以猜测出这个库的主要功能是模拟一些东西. ...

  4. Python Mock的入门学习

    一.Mock是什么 Mock这个词在英语中有模拟的这个意思,因此我们可以猜测出这个库的主要功能是模拟一些东西.准确的说,Mock是Python中一个用于支持单元测试的库,它的主要功能是使用mock对象 ...

  5. 开发神技能 | Python Mock 的入门

    Mock是什么 Mock这个词在英语中有模拟的这个意思,因此我们可以猜测出这个库的主要功能是模拟一些东西.准确的说,Mock是Python中一个用于支持单元测试的库,它的主要功能是使用mock对象替代 ...

  6. Python Mock 的入门

    Mock是什么 Mock这个词在英语中有模拟的这个意思,因此我们可以猜测出这个库的主要功能是模拟一些东西.准确的说,Mock是Python中一个用于支持单元测试的库,它的主要功能是使用mock对象替代 ...

  7. Python mock 的使用

    使用 mock 对象替换系统的一部分并且能获取它们的使用情况. 具体的说,你可以获取方法/属性的使用情况以及它们的调用参数.也可以指定返回值和设置属性. 思路是将对象设置为 mock 对象,然后根据需 ...

  8. python mock模块使用(二)

    本篇继续介绍mock里面另一种实现方式,patch装饰器的使用,patch() 作为函数装饰器,为您创建模拟并将其传递到装饰函数 官方文档地址 patch简介 1.unittest.mock.patc ...

  9. python mock模块使用(一)

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

  10. 一文熟练使用python mock

    mock作为python测试模拟对象工具,在单元测试当中使用较多,官方文档详细不够精简,这篇文章介绍mock常用的用法,以下为引用全文,留给自己和有需要的人查阅. https://realpython ...

随机推荐

  1. JDBC的连接和增删改和查找

    package Test2;import java.sql.*;import java.sql.DriverManager;import java.sql.SQLException;public cl ...

  2. What's the difference between a stub and mock?

    I believe the biggest distinction is that a stub you have already written with predetermined behavio ...

  3. 关于Delphi错误:Cannot make a visible window modal

    Delphi的fsMDIChild类型的窗体是不能使用ShowModal的,否则会弹出"Cannot make a visible window modal"异常, 但是把fsMD ...

  4. Android操作HTTP实现与服务器通信(转)

    Android操作HTTP实现与服务器通信   本示例以Servlet为例,演示Android与Servlet的通信. 众所周知,Android与服务器通信通常采用HTTP通信方式和Socket通信方 ...

  5. 初试Office 365企业版E3

    Microsoft Office 365 团队给了所有现任的MVP 12个月的微软 Office 365 企业 E3 订阅,今天激活账号并试用了一下,发现非常强大,本文简要介绍下Office 365 ...

  6. Logging with NLog

    相比较log4net, 我更喜欢NLog, 因为NLog 更简单, 而且配置选项也更加的清楚,可能是因为log4net 是从log4j 移植过来的一个原因吧,总感觉有很多的java 成分在. 要使用N ...

  7. 仿花田:相亲网站 意中人 已在GitHub上开源

    在园友的强烈呼唤下,我还是负责任的分享给大家,因为对代码比较熟悉一下,还是有些问题要说明,不然别人看起来会比较费劲.说实话除了这个bootstrap的界面风格和这件事情本身对大家有吸引力之外,内部的逻 ...

  8. 使用 SailingEase WinForm 框架构建复合式应用程序(插件式应用程序)

    对于一些较小的项目,具备一定经验的开发人员应该能够设计和构建出便于进行维护和扩展的应用程序.但是,随着功能模块数量(以及开发维护这些部件的人员)的不断增加,对项目实施控制的难度开始呈指数级增长. Sa ...

  9. Python调用C++的DLL

    import os import sys from ctypes import * test = cdll.LoadLibrary('D:\Python27\py.dll') print test.A ...

  10. 一种Flash页游前端3D转2D显示技术——PV2D, 颠覆传统吧!

    stage3D很强大,但是客户端硬件加速支持有限. 出来的图形锯齿严重,看上去和果冻一样. Stage3d不兼容2d模式. 总的来说,3D很美好,现实很残酷.但是3D有无可比拟的优势:那就是节省90% ...