什么是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. Centos7 编译安装 Nginx PHP Mariadb Memcached 扩展 ZendOpcache扩展 (实测 笔记 Centos 7.3 + Mariadb 10.1.20 + Nginx 1.10.2 + PHP 7.1.0 + Laravel 5.3 )

    环境: 系统硬件:vmware vsphere (CPU:2*4核,内存2G,双网卡) 系统版本:CentOS-7-x86_64-Minimal-1611.iso 安装步骤: 1.准备 1.0 查看硬 ...

  2. C\C++中声明与定义的区别

    声明和定义是完全同的概念,声明是告诉编译器"这个函数或者变量可以在哪找到,它的模样像什么".而定义则是告诉编译器,"在这里建立变量或函数",并且为它们分配内存空 ...

  3. Spket在Eclipse下的安装和配置(图文教程)

    一.Spket简介 Spket是一个RIA的开发工具,具有代码自动完成.语法高亮.内容概要等功能,可以帮助开发人员高效的编写JavaScript程序. 效果图: 二.安装Spket 1.去官网(htt ...

  4. JavaScript判断移动端及pc端访问不同的网站

    JavaScript判断移动端及pc端访问不同的网站 现在很多网站都是分为两个版本,一个pc端的一个移动端的(响应式除外),针对这两个版本,就需要对访问的设备进行判断,如果是pc,就直接访问pc网站, ...

  5. matlab size、numel、length、fix函数的使用,补充nargin

    size():获取矩阵的行数和列数 (1)s=size(A), 当只有一个输出参数时,返回一个行向量,该行向量的第一个元素时矩阵的行数,第二个元素是矩阵的列数.(2)[r,c]=size(A), 当有 ...

  6. Apache许可协议Open RIA Services

    Jeff Handley's进行了多年的项目--基于一份开源许可发布WCF RIA Services.遵循Apache 2许可,捐赠给Outercurve基金会的ASP.NET Open Source ...

  7. ABP理论学习之Javascript API(理论完结篇)

    返回总目录 本篇目录 Ajax Notification Message UI block和busy 事件总线 Logging 其他工具功能 说在前面的话 不知不觉,我们送走了2015,同时迎来了20 ...

  8. Improve Your Study Habits

    1.Plan your time carefully. Make a list of your weekly tasks.Then make a schedule or chart of your t ...

  9. WCF basicHttpBinding之Message Security Mode

    原创地址:http://www.cnblogs.com/jfzhu/p/4067873.html 转载请注明出处 前面的文章<WCF Security基本概念>介绍了WCF的securit ...

  10. JAVA spring hibernate 多数据源配置记录

    数据源配置 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http:// ...