一、为什么须要mock

        在写unittest的时候,假设系统中有非常多外部依赖,我们不须要也不希望把全部的部件都执行一遍。比方,要验证分享到微博的功能,假设每次測试的时候都要真实地把接口调用一遍,不仅效率低,制造非常多垃圾数据,还可能由于外部因素导致unittest失败。

对于有些耗时更久,或者无法简单创建測试环境的系统。真实的測试就显得更不必要。

我们仅仅须要知道代码依照预期运行,并调用了相关的外部接口。还是拿分享到微博这个功能做样例,分享部分的伪代码可能是这种:

  1. def share():
  2. """Share system generated message to weibo."""
  3. msg = generate_msg()
  4. weibo = get_weibo_client(user_id)
  5. weibo.upload(msg)

假设有一种方法,測试上面代码的时候可以执行全部的代码。可是并不实际执行weibo.upload(msg),并且还能知道每一个函数被调用了几次。每次被调用的參数,那我们測试用例就方便多了。

python中mock就是在測试的时候用来模拟外部服务的。一般以下的场景会使用到mock:

            a.数据库操作:没有必要每一次都去读写数据库

            b.HTTP 请求:网络操作非常耗时,測试的时候还要依赖外部的服务

            c.外部命令:运行系统命令,比方文件操作,进程操作等等。



二、mock的基本原理

上面也提到过。mock是替换代码中外部的服务。由于python是动态语言,一切都是对象,所以在运行之前把实例、方法、函数和变量替换掉。比方:

  1. >>> import os
  2.  
  3. >>> def myremove(filename):
  4. >>> return filename
  5.  
  6. >>> os.remove = myremove
  7. <function __main__.myremove>
  8.  
  9. >>> print os.remove('test-file')
  10. test-file

上面的样例是最简单的说明,假设把myremove改动成Mock类。然后这个类里面在调用的时候(复写 __call__)可以依据传进来的參数决定它的行为。还能记录每一次调用,你就大致了解 Mock 做了什么。



三、mock的使用

(1)怎么 mock 一个函数?

  1. from mock import Mock
  2.  
  3. myMethod = Mock()
  4. myMethod.return_value = 3
  5. myMethod(1, 'a', foo='bar')
  6.  
  7. myMethod.assert_called_with(1, 'a', foo='bar') # True
  8. myMethod()
  9. myMethod.call_count # 2

想要mock出一个函数。直接使用mock.Mock()实例。你能够在初始化的时候设定返回值myMethod = Mock(return_value=3)。也能够通过myMethod.return_value的属性来设置。

        除了return_value,你还能够mock side_effect,side_effect是一个函数或者异常。在mock的对象被调用的时候会被用相同的參数调用。

  1. myMethod = Mock(side_effect=KeyError('whatever'))
  2. myMethod()
  3.  
  4. Traceback (most recent call last):
  5. ...
  6. KeyError: 'whatever'

上面的样例就是模拟一个异常,假设side_effect是函数的话,这个函数就会被调用,能够用来动态地生成返回值。

以下的样例mock一个能够返回输入字符串长度的函数。

  1. def side_effect(str):
  2. return len(str)
  3.  
  4. myMethod = Mock(side_effect=side_effect)
  5. myMethod('sd') # 2

在unittest的时候。mock还提供了以下几种assert语句:

assert_any_call

assert_called_once_with

assert_called_with

assert_has_calls

(2)怎么 mock 一个类的方法?

要想mock一个类中的某个方法,能够使用mock提供的patch方法:

  1. import mock
  2. import Module1
  3.  
  4. @mock.patch.object(Module1.Class1, 'some_method')
  5. def test(mock_method):
  6. mock_method.return_value = 3
  7. mock_method.side_effect = some_side_effect
  8. m = Module1.Class1()
  9. m.some_method(*args, **kwargs)
  10.  
  11. assert m.some_method is mock_method
  12. m.some_method.assert_called_with(*args, **kwargs)

(3)怎么 mock 一个类?

有时候须要模拟一个函数或者类的行为。包含它全部的属性和方法,假设手动去一个个加入,实在低效并且easy出错。mock提供了autospec的功能。依据提供的模板类生成一个mock实例。

以下是mock一个函数的样例。

  1. import mock
  2.  
  3. def myFunc(a, b, c):
  4. pass
  5.  
  6. >>> mock_func = mock.create_autospec(myFunc, return_value=3)
  7. >>> mock_func(1,2,3)
  8. >>> mock_func.assert_called_with(1,2,3)
  9.  
  10. >>> mock_func('a string')
  11.  
  12. Traceback (most recent call last):
  13. ...
  14. TypeError: <lambda>() takes exactly 3 arguments (1 given)

mock 一个类和这个同样:

  1. >>> mock_class = mock.create_autospec(myClass)

(4)平时的使用方法

这里用返回值等于3,来模拟requests.post网络交互的返回值。省去了真实的网络交互。当然。也能够用一个方法返回值来代替3这个返回值。

  1. import json
  2. import mock
  3. from django.test import TestCase
  4.  
  5. class ApiTest(TestCase):
  6.  
  7. @mock.patch('apps.agent.requests.post')
  8. def test(self, mock_method):
  9. mock_method.return_value = 3
  10. mock_method.side_effect = some_side_effect
  11. res = self.client.post('/url/to/post')
  12. r = json.loads(res.content)
  13. self.assertEqual(0, r['retval'])

python第三方库系列之十九--python測试使用的mock库的更多相关文章

  1. python第三方库系列之十八--python/django test库

    django是属于python语音的web框架,要说django測试.也能够先说说python的測试.django能够用python的方式測试,当然,django也基于python封装了一个自己的測试 ...

  2. ABP框架系列之十九:(Debugging-调试)

    While it's not generally needed, you may want to step into ABP's source code while you debugging you ...

  3. Python之路【第十九篇】:爬虫

    Python之路[第十九篇]:爬虫   网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本.另外一些不常使用 ...

  4. 十九. Python基础(19)--异常

    十九. Python基础(19)--异常 1 ● 捕获异常 if VS异常处理: if是预防异常出现, 异常处理是处理异常出现 异常处理一般格式: try:     <............. ...

  5. Web 开发人员和设计师必读文章推荐【系列二十九】

    <Web 前端开发精华文章推荐>2014年第8期(总第29期)和大家见面了.梦想天空博客关注 前端开发 技术,分享各类能够提升网站用户体验的优秀 jQuery 插件,展示前沿的 HTML5 ...

  6. 踩坑系列《十》Python pip 安装问题一站式解决

    在使用Python编程语言时,难免要安装第三方库 安装一般都是在cmd命令行窗口安装 1.常规安装 ,在窗口输入 pip install 你要下载的库 这种方式一般网速比较慢,毕竟是从国外下载的 2. ...

  7. Python之路【第十九章】:Django进阶

    Django路由规则 1.基于正则的URL 在templates目录下创建index.html.detail.html文件 <!DOCTYPE html> <html lang=&q ...

  8. ComicEnhancerPro 系列教程十九:用JpegQuality看JPG文件的压缩参数

    作者:马健邮箱:stronghorse_mj@hotmail.com 主页:http://www.comicer.com/stronghorse/ 发布:2017.07.23 教程十九:用JpegQu ...

  9. SQL注入之Sqli-labs系列第二十九关(基于WAF防护的单引号报错注入)

    开始挑战第二十九关(Protection with WAF) 0x1查看源码 (1)login.php页面存在防护,只要检测到存在问题就跳转到hacked.php页面(其他信息看备注) 0x2 for ...

随机推荐

  1. jquery 分页控件(一)

    以前一直都是用别人的分页控件,虽然用得很爽,但总觉的还是自己写个小插件比较好,这个插件效果.代码等都有参照别人完成的控件.即便功能并不是那么完善,扩展性也不好,bug或许还很多.个人觉得,适合自己用就 ...

  2. sql 的错误处理功能很弱

    --下面演示了SQL错误处理的脆弱性--邹建 --演示1--测试的存储过程1create proc p1asprint 12/0if @@error<>0print '发生错误1' sel ...

  3. android studio 安装总结

    Android Studio 的安装和配置篇(Windows篇<转> http://www.jianshu.com/p/fc03942548cc# 中间gradle下载比较慢:解决方法 需 ...

  4. CentOS 7 安装 tomcat7.0

    安装tomcat: [root@admin local]# cd /usr/local[root@admin local]# tar -zxv -f apache-tomcat-7.0.29.tar. ...

  5. 【转】【iOS】导航栏那些事儿

    原文网址:http://www.jianshu.com/p/f797793d683f 参考文章 navigationItem UINavigationItem UINavigationBar UIBa ...

  6. 使用SVN小结

    自从加入团队后,开始使用SVN,以下是个人对SVN的一些认识和小结. 一.SVN是什么? SVN是版本管理工具,譬如团队进行项目开发,项目代码都储存在服务器上,成员可用SVN在本地获得并更新代码. 二 ...

  7. 初识NuGet - 概念, 安装和使用

    1. NuGet是什么? NuGet is a Visual Studio 2010 extension that makes it easy to add, remove, and update l ...

  8. extjs分组查询

    <script type="text/jscript"> var grid; Ext.onReady(function () { Ext.QuickTips.init( ...

  9. Python脚本控制的WebDriver 常用操作 <二十二> 处理alert / confirm / prompt

    测试用例场景 webdriver中处理原生的js alert confirm 以及prompt是很简单的.具体思路是使用switch_to.alert()方法定位到alert/confirm/prom ...

  10. Log Explorer使用说明

    一.介绍 Log Explorer主要用于对MSSQLServer的事物分析和数据恢复.你可以浏览日志.导出数据.恢复被修改或者删除的数据(包括执行过update,delete,drop和trunca ...