Python中的模块学习之mock模块
2017-08-10 23:31
316 查看
学习Python也有一段时间了,然而对Python中的单元测试模块这些并不是很懂,刚好,今天有点时间,就将mock模块进行学习并整理,下边进行分享:
先来看一下本文的整体框架:
![](https://img-blog.csdn.net/20170810225717377?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcGVpeWFvNDU2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
为什么要使用mock?
场景模拟1:比如有A和B两个模块,A模块中有调用到B模块的方法,但是很不幸,B模块中被A模块调用的方法由于一定的原因需要被修改,然而我们又不想让影响A模块的功能测试,所以就用到了单元测试模块unittest中的mock模块;mock模块就是模拟出一个假的B模块;
场景模拟2:有时需要为单元测试的初始设置准备一些其他的资源,但是这些资源又不太经常使用或者是使用起来比较笨拙,此时我们就可以定义一个mock对象来模拟一个需要使用的资源;mock对象用于代替测试的准备资源;
下边先来看一下mock对象都有哪些属性?知道这些属性,后续使用mock才会得心应手;
![](https://img-blog.csdn.net/20170810225857566?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcGVpeWFvNDU2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
网上看到有人将mock的方法进行了分类:
![](https://img-blog.csdn.net/20170810225951353?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcGVpeWFvNDU2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
举例说明:
1.name参数:
![](https://img-blog.csdn.net/20170810230129641?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcGVpeWFvNDU2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
从上述的举例中可以看出,name标识了唯一的一个mock(print的时候,后边会显示ID)。
2.return_value参数:
a.指定的是某个值:
![](https://img-blog.csdn.net/20170810230336779?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcGVpeWFvNDU2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
从上边的例子可以看出,当我们调用mock对象的时候,显示的就是return_value的值(也就是说mockObj是带有一定的功能的);
b.指定的是某个类的对象:
![](https://img-blog.csdn.net/20170810230449517?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcGVpeWFvNDU2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
3.side_effect参数:
a.指定的参数的值是异常
![](https://img-blog.csdn.net/20170810230521913?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcGVpeWFvNDU2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
从上边的例子可以看出,当side_effecr被设置的时候,return_value就被屏蔽了,不起作用了,上边side_effect被设置的是一个异常。
b.指定的参数的值是一个list或者tuple:
![](https://img-blog.csdn.net/20170810230549468?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcGVpeWFvNDU2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
插入:到这里居然想起了python中的生成器函数,yield的用法有点像return,返回的是一个生成器函数,当调用这个函数的时候,写在函数中的代码并没有真正执行,他只是返回了一个生成器。
看下边的例子:通过下边的函数创建出了一个生成器之后,每次执行next操作,都会返回一个值,当返回完的时候,就会抛出异常。
![](https://img-blog.csdn.net/20170810230623056?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcGVpeWFvNDU2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
4.spec参数:
a.指定的是属性组成的list
![](https://img-blog.csdn.net/20170810230700485?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcGVpeWFvNDU2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
b.指定的是一个类属性:
![](https://img-blog.csdn.net/20170810230747771?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcGVpeWFvNDU2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
正如文章开头所说,spec设置的是mock对象的属性,所以,这下,mock就有了3个属性了。
![](https://img-blog.csdn.net/20170810230906854?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcGVpeWFvNDU2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
参数个数错误的举例,这里就不给出了~~上边,mockFoo对象调用了fun2函数多次,但是有些时候,我们只是希望mock对象调用某个方法一次,所以,就有了下边的一个断言:
2.assert_called_once_with(*argSeq, **argKW)这个断言,当某个方法被多次调用的时候,它就会报错,看下边的例子:
注明:下边这个例子是接着上边的例子的,看上边,上边的例子中我们已经调用了fun1一次了,所以,下边的例子提示断言错误,并且还有次数显示呢~
![](https://img-blog.csdn.net/20170810231017745?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcGVpeWFvNDU2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
3.assert_any_call()用于检查测试的mock对象在测试例程中是否调用了方法,和前边的两个断言不一样,前边的两个只是检查最近一次的调用;看下边的例子(mock的构造仍和上边的例子一样);
![](https://img-blog.csdn.net/20170810231055159?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcGVpeWFvNDU2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
4.assert_has_calls()检查是否按照正确的顺序和正确的参数进行调用的;所以,我们需要给出一个方法的调用顺序,assert的时候按照这个顺序进行检查。
![](https://img-blog.csdn.net/20170810231124552?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcGVpeWFvNDU2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
注明:第一次assert失败是因为参数给错了哎。
还有,仔细看你会看到,fooCall中的每个元素前边都有call来修饰,这个就是表明,call后边的是一个方法,不加call是不可以的,解释器是不知道fun1是一个方法的,为了使用call这个关键字,我们就需要引入这个模块:from mock import Mock,call。
![](https://img-blog.csdn.net/20170810231233826?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcGVpeWFvNDU2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
上述例子中,我们是将mockFoo2添加到mockFoo1中,并重新命名为mock_att。或许,看到这里,你会很好奇,为什么mockFoo1._value1取到的不是100,而是一些id信息呢?因为,哈哈哈,spec只是设置的是mock对象的属性,也就是说mock对象有这些属性,但是属性的值呢~~就说不定了~
2.configure_mock():更改mock对象的return_value值。
举例说明:
![](https://img-blog.csdn.net/20170810231317444?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcGVpeWFvNDU2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
疑问:
为什么mockFoo.fun1不会显示出来fun1函数的输出或者是fun1的return_value值呢???
人为原因:sooSpec字典的写法出现错误,应该这么写:
![](https://img-blog.csdn.net/20170810231441622?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcGVpeWFvNDU2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
(value值也必须带上引号,但是最后那个异常就不需要了),这样子纠正之后,print mockFoo.fun1()显示的结果就是100.
3.mock_add_spec(aSpec, spec_set = False):这个函数就是给mock对象添加一个新的属性(mock对象原来的属性就会被擦除),第二个参数是指属性是可读可写,默认是只读,如果想让其拥有写权限,可以将其设置为true.
![](https://img-blog.csdn.net/20170810231516987?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcGVpeWFvNDU2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
4.reset_mock():将mock对象恢复到测试之前的状态,这里也就是避免了重新构造mock对象带来的开销。这里就不给出举例~
![](https://img-blog.csdn.net/20170810231614643?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcGVpeWFvNDU2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
2.call_count:mock对象被工厂调用的次数:
![](https://img-blog.csdn.net/20170810231653442?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcGVpeWFvNDU2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
此例子接着上述例子;
3.call_args:获取工厂调用时的参数(最近使用的参数):
![](https://img-blog.csdn.net/20170810231747813?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcGVpeWFvNDU2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
4.call_args_list:获取工厂调用的的所有参数,是个列表;
5.method_calls:测试一个mock对象都调用了哪些方法,结果是一个list。
![](https://img-blog.csdn.net/20170810231830317?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcGVpeWFvNDU2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
6.mock_calls:显示工厂调用和方法调用,下图所示:
![](https://img-blog.csdn.net/20170810231854912?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcGVpeWFvNDU2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
关于mock模块的分享,就先到这里了~后续会继续更新其他的模块的学习~对了,如果上述分享内容有疑问,请记得留言呦~感谢你~
愿我所爱之人都能实现自己的梦想~愿大家都有美好的前程~
先来看一下本文的整体框架:
为什么要使用mock?
场景模拟1:比如有A和B两个模块,A模块中有调用到B模块的方法,但是很不幸,B模块中被A模块调用的方法由于一定的原因需要被修改,然而我们又不想让影响A模块的功能测试,所以就用到了单元测试模块unittest中的mock模块;mock模块就是模拟出一个假的B模块;
场景模拟2:有时需要为单元测试的初始设置准备一些其他的资源,但是这些资源又不太经常使用或者是使用起来比较笨拙,此时我们就可以定义一个mock对象来模拟一个需要使用的资源;mock对象用于代替测试的准备资源;
下边先来看一下mock对象都有哪些属性?知道这些属性,后续使用mock才会得心应手;
网上看到有人将mock的方法进行了分类:
一、构造器
init是mock对象的构造器,name是mock对象的唯一标识;spec设置的是mock对象的属性,可以是property或者方法,也可以是其他的列表字符串或者其他的python类;return_value设置的是,当这个mock对象被调用的时候,显示出的结果就是return_value的值;side_effect是和return_value是相反的,覆盖了return_value,也就是说当这个mock对象被调用的时候,返回的是side_effect的值,而不是return_value。举例说明:
1.name参数:
从上述的举例中可以看出,name标识了唯一的一个mock(print的时候,后边会显示ID)。
2.return_value参数:
a.指定的是某个值:
从上边的例子可以看出,当我们调用mock对象的时候,显示的就是return_value的值(也就是说mockObj是带有一定的功能的);
b.指定的是某个类的对象:
3.side_effect参数:
a.指定的参数的值是异常
从上边的例子可以看出,当side_effecr被设置的时候,return_value就被屏蔽了,不起作用了,上边side_effect被设置的是一个异常。
b.指定的参数的值是一个list或者tuple:
插入:到这里居然想起了python中的生成器函数,yield的用法有点像return,返回的是一个生成器函数,当调用这个函数的时候,写在函数中的代码并没有真正执行,他只是返回了一个生成器。
看下边的例子:通过下边的函数创建出了一个生成器之后,每次执行next操作,都会返回一个值,当返回完的时候,就会抛出异常。
4.spec参数:
a.指定的是属性组成的list
b.指定的是一个类属性:
正如文章开头所说,spec设置的是mock对象的属性,所以,这下,mock就有了3个属性了。
二、mock的断言:
1.assert_called_with(*argSeq, **argKW):检查mock方法是否获得了正确的参数;当至少有一个参数有错误的值或者类型时,当参数的个数出错时,当参数的顺序不正确时,这个断言就会发生错误。参数个数错误的举例,这里就不给出了~~上边,mockFoo对象调用了fun2函数多次,但是有些时候,我们只是希望mock对象调用某个方法一次,所以,就有了下边的一个断言:
2.assert_called_once_with(*argSeq, **argKW)这个断言,当某个方法被多次调用的时候,它就会报错,看下边的例子:
注明:下边这个例子是接着上边的例子的,看上边,上边的例子中我们已经调用了fun1一次了,所以,下边的例子提示断言错误,并且还有次数显示呢~
3.assert_any_call()用于检查测试的mock对象在测试例程中是否调用了方法,和前边的两个断言不一样,前边的两个只是检查最近一次的调用;看下边的例子(mock的构造仍和上边的例子一样);
4.assert_has_calls()检查是否按照正确的顺序和正确的参数进行调用的;所以,我们需要给出一个方法的调用顺序,assert的时候按照这个顺序进行检查。
注明:第一次assert失败是因为参数给错了哎。
还有,仔细看你会看到,fooCall中的每个元素前边都有call来修饰,这个就是表明,call后边的是一个方法,不加call是不可以的,解释器是不知道fun1是一个方法的,为了使用call这个关键字,我们就需要引入这个模块:from mock import Mock,call。
三、mock的管理方法:
1.attach_mock():将一个mock对象添加到另一个mock对象中;上述例子中,我们是将mockFoo2添加到mockFoo1中,并重新命名为mock_att。或许,看到这里,你会很好奇,为什么mockFoo1._value1取到的不是100,而是一些id信息呢?因为,哈哈哈,spec只是设置的是mock对象的属性,也就是说mock对象有这些属性,但是属性的值呢~~就说不定了~
2.configure_mock():更改mock对象的return_value值。
举例说明:
疑问:
为什么mockFoo.fun1不会显示出来fun1函数的输出或者是fun1的return_value值呢???
人为原因:sooSpec字典的写法出现错误,应该这么写:
(value值也必须带上引号,但是最后那个异常就不需要了),这样子纠正之后,print mockFoo.fun1()显示的结果就是100.
3.mock_add_spec(aSpec, spec_set = False):这个函数就是给mock对象添加一个新的属性(mock对象原来的属性就会被擦除),第二个参数是指属性是可读可写,默认是只读,如果想让其拥有写权限,可以将其设置为true.
4.reset_mock():将mock对象恢复到测试之前的状态,这里也就是避免了重新构造mock对象带来的开销。这里就不给出举例~
四、mock的统计:
1.called:跟踪mock对象所做的任意调用的访问器;2.call_count:mock对象被工厂调用的次数:
此例子接着上述例子;
3.call_args:获取工厂调用时的参数(最近使用的参数):
4.call_args_list:获取工厂调用的的所有参数,是个列表;
5.method_calls:测试一个mock对象都调用了哪些方法,结果是一个list。
6.mock_calls:显示工厂调用和方法调用,下图所示:
关于mock模块的分享,就先到这里了~后续会继续更新其他的模块的学习~对了,如果上述分享内容有疑问,请记得留言呦~感谢你~
愿我所爱之人都能实现自己的梦想~愿大家都有美好的前程~
相关文章推荐
- Python模块学习 ---- threading 多线程控制和处理
- Python模块学习 --- urllib 分类: python 2013-06-09 16:17 209人阅读 评论(0) 收藏
- python os 模块学习
- Python学习之模块间互相调用方法详解
- python模块学习----nmap模块
- Python入门学习笔记之Python模块
- Python 爬虫学习笔记二: xpath 模块
- Python模块学习笔记— —time与datatime
- Python模块学习 ---- logging 日志记录
- python中openpyxl模块学习知识点(一)
- python学习笔记(三):python构建与安装模块
- Python模块学习之HTMLTestRunner生成测试报告
- python模块学习之__future__
- [zz]很详细,涵盖了多数场景!推荐 - python 的日志logging模块学习
- Python模块学习:subprocess 创建子进程
- Python学习笔记5―Python模块
- python模块学习---optparse
- python学习笔记七——模块和包
- python日志体系logging模块学习