一 : PowerMock实战手册
Programming
系列丛书
PowerMock实战
手册作者
创建时间
版本
QQ汪文君2014-10-11.0.0532500648
mock PowerMock实战手册
Programming系列丛书更改履历
mock PowerMock实战手册
Programming系列丛书
目录
前言.....................................................................................................................................................6
1、为什么要写电子书..............................................................................................................6
2、为什么要总结PowerMock...............................................................................................7
3、分享是一种美德..................................................................................................................8
4、感谢.......................................................................................................................................8如何阅读.............................................................................................................................................9参考资料.............................................................................................................................................9适合人群.............................................................................................................................................9
一、PowerMock介绍...................................................................................................................10
1.1、PowerMock不是重复发明轮子.................................................................................10
1.2、PowerMock解决了什么问题......................................................................................11
1.3、如何获得PowerMock..................................................................................................11
1.4、如何安装PowerMock..................................................................................................12
二、PowerMock入门...................................................................................................................12
2.1、使用场景.........................................................................................................................12
2.2、PowerMock之HelloWorld.......................................................................................14
2.2.1、获取所有员工的个数..........................................................................................14
2.2.2、创建员工..............................................................................................................17
2.3、重点API解释.................................................................................................................18
2.3.1、Mock...................................................................................................................18
2.3.2、Do..when..then.................................................................................................18
mock PowerMock实战手册
Programming系列丛书
2.3.3、Verify...................................................................................................................19
2.4、总结.................................................................................................................................19
三、MockLocalVariable...........................................................................................................19
3.1、有返回值.........................................................................................................................19
3.2、局部变量的void方法...................................................................................................22
3.3、@RunWith和@PrepareForTest介绍......................................................................23
3.4、总结.................................................................................................................................24
四、MockStatic...........................................................................................................................25
4.1、问题场景.........................................................................................................................25
4.2、单元测试.........................................................................................................................26
4.3、使用Mock......................................................................................................................27
五、Verifying................................................................................................................................28
扩展:powermock 实战 / powermock / powermockito
5.1、使用场景.........................................................................................................................28
5.2、业务代码.........................................................................................................................29
5.3、测试代码.........................................................................................................................31
5.4、Verifying其他API........................................................................................................33
六、Mockfinal.............................................................................................................................33
6.1、业务代码.........................................................................................................................33
6.2、EasyMock测试.............................................................................................................34
6.3、PowerMock测试..........................................................................................................37
七、Mockconstructors.............................................................................................................38
7.1、使用场景.........................................................................................................................38
mock PowerMock实战手册
Programming系列丛书
7.2、业务代码.........................................................................................................................38
7.3、PowerMock测试..........................................................................................................39
7.4、whenNew语法.............................................................................................................40
八、ArgumentsMatcher...........................................................................................................41
8.1、使用场景.........................................................................................................................41
8.2、业务代码.........................................................................................................................41
8.3、PowerMock测试..........................................................................................................42
九、Answerinterface.................................................................................................................44
9.1、使用场景.........................................................................................................................44
9.2、业务代码.........................................................................................................................44
9.3、PowerMock测试..........................................................................................................45
9.4、answer接口中参数InvocationOnMock.................................................................46
十、Mockingwithspies..............................................................................................................47
10.1、使用场景.......................................................................................................................4710.2、PowerMock测试.......................................................................................................4810.3、何时使用Spy...............................................................................................................49十一、Mockingprivatemethods...........................................................................................49
11.1、使用场景.......................................................................................................................4911.2、业务代码.......................................................................................................................5011.3、PowerMock测试.......................................................................................................50十二、总结.....................................................................................................................................51
mock PowerMock实战手册
Programming系列丛书
前言
以前很讨厌看别人写的书中有《前言》这种东西,但是随着自己编写的资料越来越多,也越来越觉得写这种东西的必要性,因为在这个章节中可以和之前的读者解释一些东西,或者表达一些自己的想法,当然你也可以理解为发牢骚。[www.61k.com)
1、为什么要写电子书
回想从开始总结的第一天开始已经有过去了五个年头,我虽然产量不高,但是已经有11本电子书在互联网上传播,很多时候周围的人问我你为什么写这些东西,你的那破玩意又不能赚钱,这要从08年说起,我记得当时做一个关于webservices的项目,当时在网上的资料不多,官方文档由于本人当时英语能力很差,阅读起来相当费劲,幸好找到了一个webservice群,群主和其中的一些成员写了两本关于Axis和xfire的电子书,很完整,总结的很用心,通过阅读这两本电子书我得以顺利完成项目,记得当时也是一个职场新人,第一次感受到来自互联网非常系统的帮助,作者文笔幽默,废话很少,写的很细致,看得出来是一位非常用心的人,后来我们也成了互联网上的好朋友,每次百度或者谷歌一些中文资料,很多人都在相互抄袭,或者原创的一些文档总是站在自己的角度去思考和撰写文档,因此我在思考,自己能否在闲暇之余也通过较为具体,能让所有的人都能够明白的写作方式,让他们懂得某种框架,某种技术,虽然力量绵薄到可以忽略不计,但是长年累月从我收到的各种反馈来看似乎也帮到了一些人,不管是他们对你的赞美还是他们对你写作过程中问题的指责,相互的成长已经让我不能停下总结的脚步。
扩展:powermock 实战 / powermock / powermockito
关于另外一个原因是,口头表达有时候不能够说明一些问题,比如我发音IP和RP在别人听来一直是同一个东西,虽然我自己分的很清楚,但是项目组的同事们都觉得我是在说
mock PowerMock实战手册
Programming系列丛书
同一个东西,这让我很苦恼,还有诸如此类的Security,我将重音放在了第一个音节,其实他是第二个音节,所以写出来和大家交流会显得更加具体。[www.61k.com)
2、为什么要总结PowerMock
Chad一直在和我说一个很重要的观点,我们项目组发布出去的产品不可能存在问题,要有问题也是操作不当引起的,Chad为什么会一直强调这样的一个观点,原因就是我们一直在做持续集成,一个小时一次的全量单元测试,而且单元测试还在不断的完善,不断的增加,几个月以来我们的持续集成环境单元测试运行次数已经超过5000多次,这样的产品质量想出问题真的不是一件容易的事情,我们之间还探讨了关于Freebug的话题(零bug),一致认为软件的质量原因有如下几个:
1、架构设计的问题
2、软件编码的问题
3、产品设计和需求分析的题
4、运行环境的问题
其中第二个问题真的可以在单元测试的过程中,以及不断的持续集成过程中让他逐渐的趋于零,当然这是需要一个很漫长的过程,在单元测试中不断的修复,不断的重构直到他不断的趋于完美是完全有可能做到的,这也是为什么要总结一下使用PowerMock的原因,或许有些读者会认为PowerMock已经是一个快要进博物馆的技术了,为什么还要专门来编写书籍去教大家怎么用,再说了互联网上零零碎碎的知识点足够让所有人掌握这一个测试框架,的确是这样的,但是一群人觉得毫无帮助,不代表所有人觉得毫无帮助,据我了解到的国内还真的有很少比例的公司在做持续集成的开发,如果您是一个PowerMock的老手,
mock PowerMock实战手册
Programming系列丛书
看到我的电子书希望能够指正其中的问题,如果您是一个新手希望使用这个框架或者想更加的系统学习这个框架,也许能够带给你一些帮助,不信,走着瞧!
3、分享是一种美德
任何时候都不要觉得自己的分享是毫无价值的,最起码你做到了对某个知识点的系统梳理,在梳理的过程中你会有更多的思考,将您的思考过程以及系统知识整理出来可以让您巩固该知识点并且当作一个复习的资料,如果更进一步的话,那么就分享出来吧,很多人都很想看您是如何思考一个问题,您的思考过程是怎样的,这真的是一件非常有趣的事情,如果您觉得您的文笔不足以描述您所掌握的知识点,那么教会我吧,我个人认为文笔还算不错,交代某些事情还是能够做到条理清晰的,除了我自认为在程序员中我文笔不错之外,我还认为自己是程序员中最帅的一个,当然很多人对此视而不见甚至不承认罢了。[www.61k.com]
4、感谢
如同我之前讨厌所谓的前言一样,我之前也是不怎么待见《感谢》,但是当自己在一路成长的过程中得到了很多人的支持和帮助,就想找到一个比较书面的机会,默默的表达自己心中的感激,如果有一天他们不小心看到了这样的文字,说不定会流出两行滚烫的泪水,哈哈,感谢我经历的四家公司,在所在的团队从来没有出现过别人抱怨的事情,我总觉得我们之间的协作是如此的融洽,每一个人都是那样的无私,都是那样的乐于分享,让我在成长的过程中收到了很多技术上面的知识,态度上面的纠正,如此这些不仅在影响着我的工作,也影响着我对待生活的方式,感谢和所有团队同事相处的每一次机会,另外要感谢我的家庭,他们包容着我一直宅在家里,还有有时候的坏脾气。
好了废话不多说了,开始我们的PowerMock之旅吧!
mock PowerMock实战手册
Programming系列丛书
如何阅读
本文中的文字排版主要有如下几种,主要是为了方便您的阅读而专门设定:
正常字体,主要是本书中的主要字体
粗体字体主要是为了表达一个很重要的观点斜体加粗主要是为了抛出某个问题代码片段是灰色背景
输出代码是黑色背景绿色字体
参考资料
1、PowerMock的官方资料,本文中几乎所有的知识点都是来自官网的文档,官方地址为:http://code.google.com/p/powermock/
2、《InstantMockTestingwithPowerMock》本书较为系统的介绍了PowerMock,但是当您看我这本书的时候,完全可以不用理会该书,因为我表达的比它要清楚很多,但是它的确是一本很详细系统的介绍PowerMock的书。(www.61k.com]
适合人群
为了能更好的吸收本文中的知识点,并且能够理解其中的代码片段,希望您具备如下几个知识体系,否则会有些困难。
1、熟悉Java
2、熟悉Junit
mock PowerMock实战手册
Programming
系列丛书
3、熟悉EasyMock
4、熟悉Mockito
一、PowerMock介绍
1.1、PowerMock不是重复发明轮子
在Java的TDD领域已经有如此多的Mock框架,比如EasyMock,JMock,Mockito为什么还要有PowerMock的存在,上述三个已经有重复发明轮子的嫌疑,为什么还要大家去使用PowerMock呢?
其实PowerMock并不是重发发明轮子,他的出现只是为了解决上述三种框架根本没有办法完成的工作,比如Mock一个Static方法等等,更多的将PowerMock理解为对现有Mock框架的扩展和进一步封装是比较贴切的,PowerMock现在目前提供了两套UT(UnitTest)框架的封装,请看下图。[www.61k.com)
PowerMock主要围绕着Junit测试框架和TestNg测试框架进行,其中在每个框架下面对所涉及的Mock框架仅仅支撑EasyMock和Mockito,为什么要画这个图呢,是因为PowerMock对所依赖的Jar包非常的苛刻,如果出现某个依赖包的冲突或者不一致都会出现不能使用的情况,因此根据您的喜好和擅长,请选择官网上提供的PowerMock套件,本文中采用的是Junit+PowerMock+Mockito这样的组合来进行讲述的。
mock PowerMock实战手册
Programming
扩展:powermock 实战 / powermock / powermockito
系列丛书
1.2、PowerMock解决了什么问题
那么到底PowerMock解决了哪些问题,PowerMock的官方文档说的非常的清楚,他们解决了如下的问题.
PowerMockisaframeworkthatextendothermocklibrariessuchasEasyMockwithmorepowerfulcapabilities.PowerMockusesacustomclassloaderandbytecodemanipulationtoenablemockingofstaticmethods,constructors,finalclassesandmethods,privatemethods,removalofstaticinitializersandmore.
使用过EasyMock或者Mockito的人应该非常清楚,他们两个无法完成对final类型的class和method的mock操作,不能完成对类方法(static)的mock,不能完成对局部变量的mock等等,PowerMock的出现就是为了解决诸如此类的问题,简言之就是专治各种不服。(www.61k.com]
1.3、如何获得PowerMock
您可以在PowerMock的官方网站免费获得测试组件,我之前说过PowerMock对所依赖的library有些苛刻,因此最好还是老老实实用它提供的套件包,如下所示,您可以下载我红色标注出来的测试套件。
mock PowerMock实战手册
Programming系列丛书
如果您是Maven的忠实用户,您可以用将如下的配置信息放到您的POM文件中,这样依赖您也会获得PowerMock和他所依赖的第三方包。(www.61k.com)
<properties>
<powermock.version>1.5.6</powermock.version>
</properties>
<dependencies>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
1.4、如何安装PowerMock
在1.3中已经很清楚的讲述了如何获得PowerMock的安装包,相信如何安装是非常简单的事情,加载到对应的classpath中即可,不再赘述了。
二、PowerMock入门
2.1、使用场景
在现实的软件开发过程中,我们经常需要协同其他同事一起来完成某个模块的功能开发,或者需要第三方资源,比如您需要一个短信网关,您需要一个数据库,您需要一个消息中间件,当您进行测试依赖于这些资源的代码时候,不可能在每次都具备相应的环境,这将
mock PowerMock实战手册
Programming
系列丛书
是一个很不现实的问题,如果当您依赖于其他模块而无法进行单元测试的时候,此时该模块的质量风险就有两个,第一是您所负责的代码,第二是您所依赖的代码,您所依赖您没有办法在很快的时间协调到资源,那么您所负责的代码由于不具备单元测试环境没有办法进行测试,很可能存在极大的风险,因此如何测试您的代码,让他的质量达到百分之百的可用,这就是Mock存在的必要,如果您还不能清楚这个场景,我们举一个大家都耳熟能详的例子来探讨一下。[www.61k.com)
采用三层架构的方式实现某个WEB的请求到业务受理,已经变得非常成熟,甚至现在在更多的分层,更多的细化每一个层次的职责,尽量使某一个层次可以最大化的重用,减少耦合,下图您应该非常熟悉了吧。
那么请大家思考如下几个问题:
1、如何保证各个层次模块的代码完全可用,在正常和临界情况下?
2、您使用集成测试做单元测试么?
很多人所谓的测试恐怕更多的是一种集成测试,也就是点击页面某个按钮看看是否能够顺利执行,所依赖的各种资源都必须正常运行,如果出现问题就很难让整个流程执行下去,如上图所示,我们如何在没有数据库的时候能够测试我们的Service,没有PaymentGate的时候进行支付的测试等等,这才是Mock要解决的问题,请注意是Mock而不是
mock PowerMock实战手册
Programming系列丛书
PowerMock(PowerMock也是一种Mock,但是他主要是解决其他Mock不能解决的问题)
2.2、PowerMock之HelloWorld
如果您已经理解了2.1中所表达的观点,那么我们就开始一个简单的例子,让大家先对PowerMock有一个比较具象的认识,然后我们在接下来的文章将一一演示如何使用强大的PowerMock,在这个世界上程序员是最最热爱世界的一类人群,因为他们在学习任何一门语言,学习任何一个框架,都要问候世界好多次。(www.61k.com]
2.2.1、获取所有员工的个数
我们现在有一个Service类,就是EmployeeService,其中有一个方法需要获取数据库中雇员的数量,Service代码如下所示:
packagecom.wangwenjun.powermock.helloworld.service;
importcom.wangwenjun.powermock.helloworld.dao.EmployeeDao;
publicclassEmployeeService{
privateEmployeeDaoemployeeDao;
publicEmployeeService(EmployeeDaoemployeeDao)
{
this.employeeDao=employeeDao;
}
/**
*获取所有员工的数量.
*@return
*/
publicintgetTotalEmployee()
{
returnemployeeDao.getTotal();
}
mock PowerMock实战手册
Programming系列丛书
}
可以看到,创建Service的时候需要传递一个EmployeeDao这个类,也就是说Service依赖于Persistence,如果想要测试Service就需要完全看Persistence的脸色,我们再来看看Persistence代码,如下所示
packagecom.wangwenjun.powermock.helloworld.dao;
publicclassEmployeeDao{
publicintgetTotal()
{
thrownewUnsupportedOperationException();
}
}
扩展:powermock 实战 / powermock / powermockito
哇!你死定了,你肯定调用不了Dao,无法正常完成Service的测试,我为什么要在Persistence的方法抛出UnsupportedOperationException呢?目的就是告诉大家该方法可能由于某种原因(没有完成,或者资源不存在等)无法为Service服务,难道你不需要测试EmployeeService么?肯定要测试,那么我们就硬着头皮来写测试用例吧。[www.61k.com)测试代码如下所示
packagecom.wangwenjun.powermock.helloworld.service;
importstaticorg.junit.Assert.assertEquals;
importorg.junit.Test;
importcom.wangwenjun.powermock.helloworld.dao.EmployeeDao;
publicclassEmployeeServiceTest{
@Test
publicvoidtestGetTotalEmployee(){
finalEmployeeDaoemployeeDao=newEmployeeDao();
finalEmployeeServiceservice=newEmployeeService(employeeDao);inttotal=service.getTotalEmployee();
assertEquals(10,total);
}
}
mock PowerMock实战手册
Programming
系列丛书
上面的测试肯定会是以失败收场,大家都已经心知肚明了,但是我还是要无情的运行一次,真的勇士敢于面对惨淡的人生,当我们执行该unittest的时候会有如下的惨痛结局。[www.61k.com)
请大家忘记此时此刻我抛出来的异常,幻想成此时此刻数据库连接不上,问题现在很明显,数据库链接不通,我们无法测试Service,难道真的就无计可施了么?好吧,有请我们的主角PowerMock闪亮登场,请看下面的测试用例packagecom.wangwenjun.powermock.helloworld.service;
importstaticorg.junit.Assert.assertEquals;
importorg.junit.Test;
importorg.powermock.api.mockito.PowerMockito;
importcom.wangwenjun.powermock.helloworld.dao.EmployeeDao;
publicclassEmployeeServiceTest{
@Test
publicvoidtestGetTotalEmployeeWithMock(){
EmployeeDaoemployeeDao=PowerMockito.mock(EmployeeDao.class);
PowerMockito.when(employeeDao.getTotal()).thenReturn(10);
EmployeeServiceservice=newEmployeeService(employeeDao);
inttotal=service.getTotalEmployee();
assertEquals(10,total);
}
}
当你再次运行时你会发现此时此刻运行通过,编写一下上述的代码我们先来有个简单的认识,所谓Mock就是创建一个假的,Mock那个对象就会创建一个假的该对象,此时该对象是一单纯的白纸,需要你对其进行涂鸦,第二句话when...then语法就是您的涂鸦,您期望调用某个方法的时候返回某个您指定的值,最后的代码已经非常熟悉了,此时此刻您已
mock PowerMock实战手册
Programming系列丛书
经完全让EmployeeDao根据你的意愿来运行,所以想怎样测试EmployeeService就怎样测试。(www.61k.com)
2.2.2、创建员工
我们再来增加另外一个需求,就是创建一个Employee,这就意味着我们需要分别在Service和Dao中增加相应的两个接口,请看代码如下所示
Service中的CreateEmployee方法
publicvoidcreateEmployee(Employeeemployee)
{
employeeDao.addEmployee(employee);
}
再来看看Dao中的方法addEmployee
publicvoidaddEmployee(Employeeemployee)
{
thrownewUnsupportedOperationException();
}
至于addEmployee为什么抛出异常,在不多做解释了,同样如果针对createEmployee写单元测试运行结果肯定死得很惨,因为此时“数据库资源不存在”,相信大家一定很清楚这一点,但是这不是本小节中所要讲述的重点,重点在于addEmployee方法是一个void类型的,也就是我们没有办法断言想要的结果是否一致,而mock厚的addEmployee方法事实上是什么都不会做的,此时我们该如何进行测试呢?
简单思考一下我们其实只是想要知道addEmployee方法是否被调用过即可,当然我们可以假设他add成功或者失败,这就根据您的testcase来设定了,好了,有了这个概念之后我们来看看如何测试void方法,其实就是mock中一个很重要的概念Verifying了。@Test
publicvoidtestCreateEmployee(){
EmployeeDaoemployeeDao=PowerMockito.mock(EmployeeDao.class);
Employeeemployee=newEmployee();
mock PowerMock实战手册
Programming系列丛书
PowerMockito.doNothing().when(employeeDao).addEmployee(employee);EmployeeServiceservice=newEmployeeService(employeeDao);
service.createEmployee(employee);
//verifythemethodinvocation.
Mockito.verify(employeeDao).addEmployee(employee);
}
然后用junit运行肯定能够通过,其中Mockito.verify主要用来校验被mock出来的对象中的某个方法是否被调用,我们的PowerMockhelloworld也到此结束了。(www.61k.com]
2.3、重点API解释
其中有几个API大家可能看着有点陌生,不用担心,在接下来的章节中会大量的使用到,慢慢您会熟悉起来的,我们简单说说在上面的代码中所涉及到的几个PowerMockAPI
2.3.1、Mock
Powermockito.mock()方法主要是根据class创建一个对应的mock对象,powermock的创建方式可不像easymock等使用proxy的方式创建,他是会在你运行的过程中动态的修改class字节码文件的形式来创建的。
2.3.2、Do..when..then
我们可以看到,每次当我们想给一个mock的对象进行某种行为的预期时,都会使用do...when...then...这样的语法,其实理解起来非常简单:做什么、在什么时候、然后返回什么。
mock PowerMock实战手册
Programming系列丛书
2.3.3、Verify
当我们测试一个void方法的时候,根本没有办法去验证一个mock对象所执行后的结果,因此唯一的方法就是检查方法是否被调用,在后文中将还会专门来讲解。(www.61k.com]
扩展:powermock 实战 / powermock / powermockito
2.4、总结
其实Helloworld有关PowerMock所表现出来的功能,在EasyMock中照样是可以实现的,并不能说明powermock扩展了什么,其实这不是我所表达的重点,我只是想让读者对如何使用PowerMock有一个简单的认识。
既然说道本节中所设计的示例并没有体现出来PowerMock的优势,那么请耐着性子往下再去阅读,另外在本章中有很多东西描述的很罗嗦,目的是为了让大家能够了解的清楚一些.
三、MockLocalVariable
3.1、有返回值
在本章中我们设计一个其他Mock玩不转的东东,但是在编码的时候会经常遇到,我们先来看看Service的代码
packagecom.wangwenjun.powermock.local.service;
importcom.wangwenjun.powermock.local.dao.EmployeeDao;
publicclassEmployeeService{
publicintgetTotalEmployee()
{
EmployeeDaoemployeeDao=newEmployeeDao();
returnemployeeDao.getTotal();
mock PowerMock实战手册
Programming系列丛书}
}
我们并没有采用helloworld中通过构造方法注入dao的方式,而是在方法内部new出一个EmployeeDao,我们通常都会写这样的代码,根据之前的经验,调用肯定是失败的,而要测试这样的代码EasyMock,Mockito等显然力不从心,这个时候优势就很明显的体现出来了,请看下面的测试代码
packagecom.wangwenjun.powermock.local.service;
importstaticorg.junit.Assert.*;
importorg.junit.Test;
importorg.junit.runner.RunWith;
importorg.powermock.api.mockito.PowerMockito;
importorg.powermock.core.classloader.annotations.PrepareForTest;
importorg.powermock.modules.junit4.PowerMockRunner;
importcom.wangwenjun.powermock.local.dao.EmployeeDao;
@RunWith(PowerMockRunner.class)
@PrepareForTest(EmployeeService.class)
publicclassEmployeeServiceTest{
mock PowerMock实战手册
Programming系列丛书
/**
*用传统的方式肯定测试失败。(www.61k.com]
*/
@Test
publicvoidtestGetTotalEmployee(){
EmployeeServiceservice=newEmployeeService();
inttotal=service.getTotalEmployee();
assertEquals(10,total);
}
/**
*采用PowerMock进行测试
*/
@Test
publicvoidtestGetTotalEmployeeWithMock(){
EmployeeDaoemployeeDao=PowerMockito.mock(EmployeeDao.class);try{
PowerMockito.whenNew(EmployeeDao.class).withNoArguments()
.thenReturn(employeeDao);
PowerMockito.when(employeeDao.getTotal()).thenReturn(10);
EmployeeServiceservice=newEmployeeService();
mock PowerMock实战手册
Programming系列丛书
inttotal=service.getTotalEmployee();
assertEquals(10,total);
}catch(Exceptione){
fail("测试失败.");
}
}
}
运行上面的代码可以很明显的看到其中传统的方式是失败的,而通过Mock方式测试的是成功的,当然您可能会非常惊讶PowerMock尽然有如此强大的能力,以至于可以Mock出局部变量,那么同样我们再来看看局部变量的void方法该如何进行测试。[www.61k.com]
3.2、局部变量的void方法
同样在Service中增加一个添加Employee的方法,如下所示
publicvoidcreateEmployee(Employeeemployee)
{
EmployeeDaoemployeeDao=newEmployeeDao();
employeeDao.addEmployee(employee);
}
我们该如何测试这个方法呢?同样的如果采用之前的传统调用方式肯定会出现错误,我们只能采用PowerMock的方式来进行测试,测试代码如下所示:@Test
publicvoidtestCreateEmployee(){
EmployeeServiceservice=newEmployeeService();
Employeeemployee=newEmployee();
service.createEmployee(employee);
}
@Test
publicvoidtestCreateEmployeeWithMock(){
EmployeeDaoemployeeDao=PowerMockito.mock(EmployeeDao.class);
mock PowerMock实战手册
Programming
系列丛书
try{
PowerMockito.whenNew(EmployeeDao.class).withNoArguments()
.thenReturn(employeeDao);
Employeeemployee=newEmployee();
EmployeeServiceservice=newEmployeeService();
service.createEmployee(employee);
Mockito.verify(employeeDao).addEmployee(employee);
}catch(Exceptione){
fail();
}
}
运行上面的两个测试用例,你会发现其中第一个失败,第二个运行成功,对于测试void返回类型的方法,同样我们做的只能是判断他是否被调用,关于verify的话题在后文中有专门一个章节来进行讨论。[www.61k.com)
3.3、@RunWith和@PrepareForTest介绍
细心的人可能会发现,我们在编写测试代码的时候增加了两个Annotation,分别是@RunWith和@PrepareForTest,那他们的作用是什么呢?
其中@RunWith就是显式的告诉Junit使用某个指定的Runner来运行TestCase,我们使用了PowerMockRunner来运行我们的测试用例,如果不指定的话我们就默认使用的是Junit提供的Runner,先来看看下面这张图,了解一下Runner家族的成员
mock PowerMock实战手册
Programming系列丛书
由于我们在测试EmployeeService的时候需要改变EmployeeDao的创建行为,通过这个的语句PowerMockito.whenNew(EmployeeDao.class).withNoArguments().thenReturn(employeeDao);就可以看得出来,因此就需要了解另外一个注解@PrepareForTest,这个注解是告诉PowerMock为我提前准备一个xxx的class,根据我测试预期的行为去准备,根据这段粗糙的文字描述,我们再来详细的整理一下。(www.61k.com]
扩展:powermock 实战 / powermock / powermockito
在测试EmployeeService的时候,因为涉及到了局部变量的创建,我们必须让他创建成为我们想要的Mock对象,因此需要有一个录制的过程PowerMockito.whenNew(EmployeeDao.class).withNoArguments().thenReturn(employeeDao);这句话就是告诉PowerMock录制一个这样的构造行为,等我接下来用的时候你就把之前mock的东西给我,而@PrepareForTest是为PowerMock的Runner提前准备一个已经根据某种预期改变过的class,在这个例子中就是EmployeeService,如果大家使用过Jacoco统计过Java测试代码的覆盖率就会发现一个很恼火的问题,那就是不管你写了多少个EmployeeService的测试用例,只要你对其进行了PrepareForTest之后,代码覆盖率仍然是0,为什么会这样呢,因为经过了PrepareForTest的处理之后,PowerMock框架会通过类加载器的方式改变EmployeeService的行为,如何改变呢?当然是产生了一个新的类在运行的过程中,新的类里面但凡碰到要创建EmployeeDao的时候都会将提前录制好的行为重播出来,给出一个Mock对象。
3.4、总结
如果说之前PowerMock能做的事情很简单,那么本章中所涉及的Mock局部变量的方式是其他Mock框架所不能完成的,在本章中我们还学习了两个比较重要的Annotation,其中一个是RunWith,另外一个是PrepareForTest,在后面我们会大量的使用到,不用担
mock PowerMock实战手册
Programming系列丛书
心一时半会接受不了,我们还会有专门的章节讲解PowerMock的类加载器,到时候您就会明白其中更多的细节。[www.61k.com)
四、MockStatic
有时候我们写代码的时候喜欢编写已经写工具类,工具类一般都提供了大量的便捷的类方法(static)供调用者使用,在本章中我们来看看如何进行静态方法的测试。
4.1、问题场景
同样Service还是两个接口,第一个是查询雇员数量,第二个是创建一个新的雇员,代码如下所示:
packagecom.wangwenjun.powermock.mockstatic.service;
importcom.wangwenjun.powermock.Employee;
importcom.wangwenjun.powermock.mockstatic.EmployeeUtils;
publicclassEmployeeService{
publicintgetEmployeeCount(){
returnEmployeeUtils.getEmployeeCount();
}
publicvoidcreateEmployee(Employeeemployee){
EmployeeUtils.persistenceEmployee(employee);
}
}
相比这样的代码在前文中已经看得非常多了,重点是其中的一个工具类EmployeeUtils,同样来看看它的代码
packagecom.wangwenjun.powermock.mockstatic;
importcom.wangwenjun.powermock.Employee;
mock PowerMock实战手册
Programming系列丛书
publicclassEmployeeUtils{
publicstaticintgetEmployeeCount()
{
thrownewUnsupportedOperationException();
}
publicstaticvoidpersistenceEmployee(Employeeemployee)
{
thrownewUnsupportedOperationException();
}
}
4.2、单元测试
上面的两个类代码都非常简单,但是写一个专门针对EmployeeService的单元测试类,你会发现运行根本不能通过
packagecom.wangwenjun.powermock.mockstatic.service;
importstaticorg.junit.Assert.assertEquals;
importstaticorg.junit.Assert.assertTrue;
importorg.junit.Test;
importcom.wangwenjun.powermock.Employee;
publicclassEmployeeServiceTest{
@Test
publicvoidtestGetEmployeeCount(){
finalEmployeeServiceemployeeService=newEmployeeService();intcount=employeeService.getEmployeeCount();
assertEquals(10,count);
}
@Test
publicvoidtestCreateEmployee(){
finalEmployeeServiceemployeeService=newEmployeeService();Employeeemployee=newEmployee();
employeeService.createEmployee(employee);
assertTrue(true);
}
mock PowerMock实战手册
Programming系列丛书
}
上面的测试用例肯定是无法运行通过,想必一看就很清楚,所有就不再赘述,根据目前的PowerMock知识,还是不足以完成对EmployeeUtils的Mock操作,那到底应该如何对其进行测试呢,马上揭晓。(www.61k.com]
4.3、使用Mock
使用传统的方式很难对EmployeeService完成测试,因为没有办法模拟EmployeeUtils的行为,在本节中我们继续使用PowerMock完成对EmployeeService的测试,代码如下packagecom.wangwenjun.powermock.mockstatic.service;
importstaticorg.junit.Assert.assertEquals;
import
import
import
import
importorg.junit.Test;org.junit.runner.RunWith;org.powermock.api.mockito.PowerMockito;org.powermock.core.classloader.annotations.PrepareForTest;org.powermock.modules.junit4.PowerMockRunner;
importcom.wangwenjun.powermock.Employee;
importcom.wangwenjun.powermock.mockstatic.EmployeeUtils;
@RunWith(PowerMockRunner.class)
@PrepareForTest(EmployeeUtils.class)
publicclassEmployeeServiceTest{
@Test
publicvoidtestGetEmployeeCountWithMock(){
PowerMockito.mockStatic(EmployeeUtils.class);
PowerMockito.when(EmployeeUtils.getEmployeeCount()).thenReturn(10);
finalEmployeeServiceemployeeService=newEmployeeService();
intcount=employeeService.getEmployeeCount();
assertEquals(10,count);
}
@Test
publicvoidtestCreateEmployeeWithMock(){
PowerMockito.mockStatic(EmployeeUtils.class);
mock PowerMock实战手册
Programming系列丛书
Employeeemployee=newEmployee();
PowerMockito.doNothing().when(EmployeeUtils.class);
finalEmployeeServiceemployeeService=newEmployeeService();
扩展:powermock 实战 / powermock / powermockito
employeeService.createEmployee(employee);
PowerMockito.verifyStatic();
}
}
运行上述的单元测试,你就会得到正确的测试结果和预期,首先我们让PowerMock在运行之前准备EmployeeUtils类,并且我们采用了mockstatic的方法,其中这个有别于mock非静态的类,然后其他的操作就会完全一样了。(www.61k.com)
五、Verifying
Verifying是一个非常强大的测试工具,不仅在powermock中使用,就连easymock,mockito等框架都会使用,他的目的是为了检查某个被测试的方法是否顺利的被调用了,可能三言两语各位读者还是不能理解,我们举一个简单的例子,然后我们针对这样的代码进行测试。
5.1、使用场景
假设我们有一个这样的业务接口,传递一个Employee实例参数,然后通过DAO查询该Employee是否在对应的数据库中存在,如果不存在则创建一个Employee数据,否则就更新原来的Employee,其实如此简单的逻辑我根本不用画图演示,但是为了能照顾到初学者,我还是画一个简单的图示吧。
mock PowerMock实战手册
Programming
系列丛书
其中大名鼎鼎的hibernate就有一个这样的接口,通过上图我们不难看出,其中saveOrUpdate里面有两个分支的存在,而且针对每个分支可能会调用不同的DAO接口,我们来看代码吧。(www.61k.com)
5.2、业务代码
EmployeeDao.java代码如下所示:
mock PowerMock实战手册
Programming系列丛书*@paramemployee
*/
publicvoidupdateEmploye(Employeeemployee){
thrownewUnsupportedOperationException();
}
/**
*@paramemployee
*@return
*/
publiclonggetCount(Employeeemployee){
thrownewUnsupportedOperationException();}
}
同样为了模拟DAO比较难以测试,我们依旧抛出了运行时异常,好了,再来看一看Service中是如何调用的吧。[www.61k.com)
packagecom.wangwenjun.powermock.verify.service;
importcom.wangwenjun.powermock.Employee;
importcom.wangwenjun.powermock.verify.dao.EmployeeDao;
publicclassEmployeeService{
publicvoidsaveOrUpdate(Employeeemployee){
finalEmployeeDaoemployeeDao=newEmployeeDao();
longcount=employeeDao.getCount(employee);
if(count>0)
employeeDao.updateEmployee(employee);
else
employeeDao.saveEmployee(employee);
}
}
在开始编写测试代码之前,我们先来思考一下,其中Service中的saveOrUpdate方法是用了EmployeeDao,并且作为一个局部变量被实例化,因此我们必须采用PowerMock的方法进行测试,但是最重要的是由于其中多了一层逻辑判断,这给我们的断言带来了一定的难度,由于不能真正的连接数据库,所以没有办法产生真实的数据,所以我们断言的依据是什么?是新增了一条数据还是更改了一条记录呢?
mock PowerMock实战手册
Programming系列丛书
显然采用传统的方式我们更本没有办法做到这一点,但是Verifying却可以让我们很容易的应对这样一个场景,首先我们不难看出,当count大于0的时候我们就需要执行更新操作,当count小于等于0的时候我们就需要执行新增的操作,那么我们就可以通过验证DAO中所涉及的方法是否被调用来进行验证了,如果这么说您还是不能理解,接着看下面的两个测试用例。[www.61k.com)5.3、测试代码
packagecom.wangwenjun.powermock.verify.service;
importstaticorg.junit.Assert.fail;
import
import
import
import
import
importorg.junit.Test;org.junit.runner.RunWith;org.mockito.Mockito;org.powermock.api.mockito.PowerMockito;org.powermock.core.classloader.annotations.PrepareForTest;org.powermock.modules.junit4.PowerMockRunner;
importcom.wangwenjun.powermock.Employee;
importcom.wangwenjun.powermock.verify.dao.EmployeeDao;
@RunWith(PowerMockRunner.class)
@PrepareForTest(EmployeeService.class)
publicclassEmployServiceTest{
@Test
publicvoidtestSaveOrUpdateCountLessZero(){
try{
EmployeeDaoemployeeDao
PowerMockito.mock(EmployeeDao.class);
PowerMockito.whenNew(EmployeeDao.class).withNoArguments()
.thenReturn(employeeDao);
Employeeemployee=newEmployee();
PowerMockito.when(employeeDao.getCount(employee)).thenReturn(0L);
EmployeeServiceemployeeService=newEmployeeService();
employeeService.saveOrUpdate(employee);=
mock PowerMock实战手册
Programming系列丛书
Mockito.verify(employeeDao).saveEmployee(employee);
Mockito.verify(employeeDao,Mockito.never())
.updateEmploye(employee);
}catch(Exceptione){
e.printStackTrace();
fail();
}
}
@Test
publicvoidtestSaveOrUpdateCountMoreThanZero(){
EmployeeDaoemployeeDao=PowerMockito.mock(EmployeeDao.class);
try{
PowerMockito.whenNew(EmployeeDao.class).withNoArguments()
.thenReturn(employeeDao);
Employeeemployee=newEmployee();
PowerMockito.when(employeeDao.getCount(employee)).thenReturn(1L);
EmployeeServiceemployeeService=newEmployeeService();
employeeService.saveOrUpdate(employee);
Mockito.verify(employeeDao).updateEmploye(employee);
Mockito.verify(employeeDao,
Mockito.never()).saveEmployee(employee);
}catch(Exceptione){
扩展:powermock 实战 / powermock / powermockito
fail();
}
}
}
读者可以运行一下上面的两个测试用例,你会发现运行通过,上面的代码也比较简单,但是我还是要主要强调一下其中的重点,就是verify方法的使用,我们根据getCount的返回的结果去验证对应的方法是否被调用了,从而来测试我们的service是否逻辑运行正确
当然Verify的所涉及的方法还不至这些,其中有很多的verificationmodes,读者可以一一验证,我们在下一节中也将罗列出来。(www.61k.com)
mock PowerMock实战手册
Programming系列丛书
5.4、Verifying其他API
Mockito.verify(employeeDao,Mockito.never()).saveEmployee(employee);
Mockito.verify(employeeDao,
Mockito.atLeastOnce()).saveEmployee(employee);
Mockito.verify(employeeDao,
Mockito.times(1)).saveEmployee(employee);
Mockito.verify(employeeDao,
Mockito.atMost(1)).saveEmployee(employee);
Mockito.verify(employeeDao,
Mockito.atLeast(1)).saveEmployee(employee);
六、Mockfinal
本章的内容也是比较简单,就是使用PowerMock测试一下某个final修饰的class或者method,但是为了更加有说服力,本章会引入easymock作为对比(其中easymock的内容不在本书范围之内,请翻阅相关资料)看看easymock是否能够mock一个final修饰的class或者method
6.1、业务代码
其中业务代码和之前的业务代码没有什么不一样,都是一个service调用其中的一个dao,但是这个daoclass是被final修饰的,也就是说他是不能被继承的,我们看一下代码吧。[www.61k.com)
Service代码
packagecom.wangwenjun.powermock.mockfinal.service;
importcom.wangwenjun.powermock.Employee;
importcom.wangwenjun.powermock.mockfinal.dao.EmployeeDao;
/**
*和之前的业务代码没有什么太大的区别,所以只写一个方法即可
*
mock PowerMock实战手册
Programming系列丛书Dao的代码如下所示
packagecom.wangwenjun.powermock.mockfinal.dao;
importcom.wangwenjun.powermock.Employee;
finalpublicclassEmployeeDao{
publicbooleaninsertEmployee(Employeeemployee){
thrownewUnsupportedOperationException();
}
}
Service代码没有什么,重点看一下DAO的代码,修饰符多了一个final类型,同时为了能够方便EasyMock进行测试,我将EmployeeDao在EmployeeService中通过了构造方法传入(因为EasyMock不能在mock方法内部的变量)6.2、EasyMock测试
packagecom.wangwenjun.powermock.mockfinal.service;
importorg.easymock.EasyMock;
importorg.junit.Test;
importcom.wangwenjun.powermock.Employee;
importcom.wangwenjun.powermock.mockfinal.dao.EmployeeDao;
mock PowerMock实战手册
Programming系列丛书执行上面的单元测试,你会发现运行出现了错误,错误信息如下所示:
mock PowerMock实战手册
Programming系列丛书但是当您将EmployeeDao的final修饰符去掉之后就会运行成功,由此可见EasyMock是通过代理的方式实现(继承代理)产生一个新的Mock对象的,同样final修饰的方法也会不适合EasyMock的场景,读者自己进行测试吧。(www.61k.com)
mock PowerMock实战手册
Programming系列丛书
6.3、PowerMock测试
好了,我们来看看PowerMock的方式吧,其实PowerMock的方式的章节中所涉及的代码没有什么区别,出现在这里显得有点罗嗦,但是为了更加能够说明问题,我还是将代码贴出来吧,如果您觉得我多此一举,就直接将该部分的代码跳过即可。(www.61k.com]packagecom.wangwenjun.powermock.mockfinal.service;
import
import
import
import
import
importorg.junit.Test;org.junit.runner.RunWith;org.mockito.Mockito;org.powermock.api.mockito.PowerMockito;org.powermock.core.classloader.annotations.PrepareForTest;org.powermock.modules.junit4.PowerMockRunner;
importcom.wangwenjun.powermock.Employee;
importcom.wangwenjun.powermock.mockfinal.dao.EmployeeDao;
@RunWith(PowerMockRunner.class)
@PrepareForTest(EmployeeDao.class)
publicclassEmployeeServicePowerMockTest{
@Test
publicvoidtest(){
EmployeeDaoemployeeDao=PowerMockito.mock(EmployeeDao.class);
Employeeemployee=newEmployee();
PowerMockito.when(employeeDao.insertEmployee(employee))
.thenReturn(true);
EmployeeServiceemployeeService
EmployeeService(employeeDao);
employeeService.createEmployee(employee);=new
Mockito.verify(employeeDao).insertEmployee(employee);
}
}
当您运行上面的单元测试时,您会发现出现了可爱的小绿条,恭喜你,成功了!
mock PowerMock实战手册
Programming系列丛书
七、Mockconstructors
有些时候我们需要在类的构造函数中传递某些参数进去,这也是非常常见的一种编码习惯,这个时候我们应该如何去Mock这样的类呢?其实在前面的文章中已经有了相关的代码,在本章中我们继续深入探讨一下。(www.61k.com]
7.1、使用场景
举个例子,DAO的构造需要传递两个参数,其中一个是boolean类型标识是否懒加载,另外一个是enumeration类型,标识采用何种数据库方言,当然有可能构造该DAO需要很重的资源,并且在我们的单元测试环境下不一定能够很容易的获得,因此需要mock。
7.2、业务代码
我们先来看看DAO的代码
packagecom.wangwenjun.powermock.construction.dao;
importcom.wangwenjun.powermock.Employee;
publicclassEmployeeDao{
publicenumDialect{
扩展:powermock 实战 / powermock / powermockito
MYSQL,
ORACLE
}
publicEmployeeDao(booleanlazy,Dialectdialect)
{
thrownewUnsupportedOperationException();
}
publicvoidinsertEmploye(Employeeemployee)
{
thrownewUnsupportedOperationException();
mock PowerMock实战手册
Programming系列丛书
}
}
再来看看Service的代码,同样代码也是超级简单
packagecom.wangwenjun.powermock.construction.service;
importcom.wangwenjun.powermock.Employee;
importcom.wangwenjun.powermock.construction.dao.EmployeeDao;
importcom.wangwenjun.powermock.construction.dao.EmployeeDao.Dialect;publicclassEmployeeService{
publicvoidcreateEmployee(finalEmployeeemployee)
{
EmployeeDaoemployeeDao=newEmployeeDao(false,Dialect.MYSQL);
employeeDao.insertEmploye(employee);
}
}
我们测试的重点是看看如何构造出来EmployeeDao,而不再关注其中方法的调用,现在我们就来写测试用例来mock一个EmployeeDao
7.3、PowerMock测试
好了,我们一起来测试一下上面的这个Service吧,然后重点的部分我用数字标识了出来,顺便做一下探讨。(www.61k.com)
packagecom.wangwenjun.powermock.construction.service;
importstaticcom.wangwenjun.powermock.construction.dao.EmployeeDao.Dialect.MYSQL;importstaticorg.junit.Assert.fail;
importstaticorg.powermock.api.mockito.PowerMockito.mock;
importstaticorg.powermock.api.mockito.PowerMockito.whenNew;
import
import
import
import
importorg.junit.Test;org.junit.runner.RunWith;org.mockito.Mockito;org.powermock.core.classloader.annotations.PrepareForTest;org.powermock.modules.junit4.PowerMockRunner;
importcom.wangwenjun.powermock.Employee;
mock PowerMock实战手册
Programming系列丛书
importcom.wangwenjun.powermock.construction.dao.EmployeeDao;
@RunWith(PowerMockRunner.class)
@PrepareForTest(EmployeeService.class)
publicclassEmployeeServiceTest{
@Test
publicvoidtest(){
EmployeeDaoemployeeDao=mock(EmployeeDao.class);//(1)
try{
whenNew(EmployeeDao.class).withArguments(false,
MYSQL).thenReturn(
employeeDao);//(2)
EmployeeServiceemployeeService=newEmployeeService();
Employeeemployee=newEmployee();
employeeService.createEmployee(employee);
Mockito.verify(employeeDao).insertEmploye(employee);//(3)
}catch(Exceptione){
fail();
}
}
}
(1)我们首先mock了一个EmployeeDao实例
(2)我们用whenNew语法,并且委以相关的参数,注意这里的参数必须和Service中的参数一致,否则在Service中还会继续创建一个新的EmployeeDao实例。(www.61k.com]
(3)我们验证了方法的调用。
7.4、whenNew语法
我们在上面的PowerMock测试用例中看到了一个新的语法那就是whenNew,其实我们在前面的章节中都有涉猎该语法,这个语法的意思是当碰到new这个关键字时,返回某个被Mock的对象而不是让真的new行为发生,回想我们在Service中new一个新的EmployeeDao,如果我们不提前准备这个new行为,那么他会在运行期创建一个新的EmployeeDao实例,此时我们Mock出来的实例将会不起任何作用的,并且对应的参数一
mock PowerMock实战手册
Programming
系列丛书
定要一致,如果您不能确保参数的一致性,那就是用withAnyArguments,当然还有对应的很多whenNew语法,我们来一起看一下。[www.61k.com)
我就不多做赘述,自己看一看上面的截图就可以了。
八、ArgumentsMatcher
ArgumentsMatcher是一个比较强大的Mock接口,其实这并不是PowerMock的原创,其实在EasyMock,Mockito中均有相关的支持,同时它也是一个比较灵活的Mock手段,在本章中我们来一起讨论一下如何使用ArgumentsMatcher。
8.1、使用场景
有些时候我们Mock一个对象的时候,需要根据不同的参数返回不同的内容,虽然Mock的对象是假的,但是我们还是希望能够这样做,做一些临界值的测试,并且得到相关的预期结果,好了,我们先来看看业务代码,其中业务代码也比较简单,我们从最基本的Controller开始,然后通过Controller调用相应的Service。
8.2、业务代码
Controller的代码如下所示
packagecom.wangwenjun.powermock.matcher.controller;
importcom.wangwenjun.powermock.matcher.service.EmployeeService;
mock PowerMock实战手册
Programming系列丛书publicclassEmployeeController{
publicStringgetEmail(finalStringuserName){
EmployeeServiceemployeeService=newEmployeeService();
Stringemail=employeeService.findEmailByUserName(userName);
returnemail;
}
}
Service的代码如下所示packagecom.wangwenjun.powermock.matcher.service;
publicclassEmployeeService{
publicStringfindEmailByUserName(StringuserName){
thrownewUnsupportedOperationException();
}
}
根据以前的知识,我们只能Mock一个Service,并且能够预先设定一个返回结果,但是我们在编写代码的时候,提前会根据输入的参数获得不同的返回值,比如参数为Null或者一个不存在的结果等等。[www.61k.com)
总而言之,我们就像根据参数的不同而获得不同的返回结果。
8.3、PowerMock测试
packagecom.wangwenjun.powermock.matcher.controller;
扩展:powermock 实战 / powermock / powermockito
import
import
import
import
import
importstaticstaticstaticstaticstaticstaticorg.junit.Assert.assertEquals;org.junit.Assert.assertTrue;org.junit.Assert.fail;org.powermock.api.mockito.PowerMockito.mock;org.powermock.api.mockito.PowerMockito.when;org.powermock.api.mockito.PowerMockito.whenNew;
importorg.junit.Test;
importorg.mockito.ArgumentMatcher;
importorg.mockito.Mockito;
importcom.wangwenjun.powermock.matcher.service.EmployeeService;
mock PowerMock实战手册
Programming系列丛书publicclassEmployeeControllerTest{
@Test
publicvoidtestGetEmail(){
EmployeeServiceemployeeService=mock(EmployeeService.class);
when(employeeService.findEmailByUserName(Mockito.argThat(new
ArgumentMatcher<String>(){
@Override
publicbooleanmatches(Objectargument){
Stringarg=(String)argument;
if(arg.startsWith("wangwenjun")||arg.startsWith("wwj"))
returntrue;
else
thrownewRuntimeException();
}
}))).thenReturn("wangwenjun@gmail.com");
try{
whenNew(EmployeeService.class).withAnyArguments().thenReturn(employeeService);
EmployeeControllercontroller=newEmployeeController();
Stringemail=controller.getEmail("wangwnejun");
assertEquals("wangwenjun@gmail.com",email);
controller.getEmail("liudehua");
fail("shouldnotprocesstohere.");
}catch(Exceptione){
assertTrue(einstanceofRuntimeException);
}
}
}
上面的这个PowerMock测试代码,我们通过实现一个匿名ArgumentMatcher类,然后就实现了根据不同参数获得不同的返回结果预期,这样我们就可以少些很多when...thenReturn
mock PowerMock实战手册
Programming系列丛书
九、Answerinterface
其实Answer接口的作用和ArgumentsMatcher比较类似,但是它比ArgumentsMatcher更加强大,我们还是根据上一章节中的那个示例然后来说明Answer的使用方法。[www.61k.com]
9.1、使用场景
使用场景在这里还是罗嗦一下吧,当用户名是wangwenjun或者wwj的时候能够返回wangwenjun@gmail.com,当用户名是liudehua或者ldh的时候返回的是andy@gmail.com,如果用户名是其他则抛出无法找到的异常。
9.2、业务代码
其实业务代码和上一张中一模一样,但是为了方便读者能够更好的查看,就将代码罗列到这个地方了,希望不要闲多余哈。
Service代码
packagecom.wangwenjun.powermock.answer.service;
publicclassEmployeeService{
publicStringfindEmailByUserName(StringuserName){
thrownewUnsupportedOperationException();
}
}
Controller代码
packagecom.wangwenjun.powermock.answer.controller;
importcom.wangwenjun.powermock.matcher.service.EmployeeService;
publicclassEmployeeController{
publicStringgetEmail(finalStringuserName){
mock PowerMock实战手册
Programming系列丛书
EmployeeServiceemployeeService=newEmployeeService();
Stringemail=employeeService.findEmailByUserName(userName);returnemail;
}
}
9.3、PowerMock测试
一切准备就绪,我们就是用Answer来进行一下PowerMock测试,测试代码如下packagecom.wangwenjun.powermock.answer.controller;
importstaticorg.junit.Assert.assertEquals;
importstaticorg.junit.Assert.assertTrue;
importstaticorg.junit.Assert.fail;
import
import
import
import
import
import
import
importorg.junit.Test;org.junit.runner.RunWith;org.mockito.Mockito;org.mockito.invocation.InvocationOnMock;org.mockito.stubbing.Answer;org.powermock.api.mockito.PowerMockito;org.powermock.core.classloader.annotations.PrepareForTest;org.powermock.modules.junit4.PowerMockRunner;
importcom.wangwenjun.powermock.answer.service.EmployeeService;@RunWith(PowerMockRunner.class)
@PrepareForTest(EmployeeController.class)
publicclassEmployeeControllerTest{
@Test
publicvoidtestGetEmail(){
EmployeeServiceemployeeService
PowerMockito.mock(EmployeeService.class);=
PowerMockito.when(employeeService.findEmailByUserName(Mockito.anyString())).then(newAnswer<String>(){
@Override
publicStringanswer(InvocationOnMockinvocation)throws
Throwable{
Stringargument=(String)invocation.getArguments()[0];
if("wangwenjun".equals(argument))
mock PowerMock实战手册
Programming系列丛书
return"wangwenjun@gmail.com";
elseif("liudehua".equals(argument))
return"andy@gmail.com";
thrownewNullPointerException();
}
});
try{
PowerMockito.whenNew(EmployeeService.class).withNoArguments().thenReturn(employeeService);
EmployeeControllercontroller=newEmployeeController();
Stringemail=controller.getEmail("wangwenjun");
assertEquals("wangwenjun@gmail.com",email);
email=controller.getEmail("liudehua");
assertEquals("andy@gmail.com",email);
email=controller.getEmail("JackChen");
fail("shouldnotprocesstohere.");
}catch(Exceptione){
扩展:powermock 实战 / powermock / powermockito
assertTrue(einstanceofNullPointerException);
}
}
}
9.4、answer接口中参数InvocationOnMock
invocation.getArguments();(1)
invocation.callRealMethod();(2)
invocation.getMethod();(3)
invocation.getMock();(4)
(1)获取mock方法中传递的入参
(2)获取是那个真实的方法调用了该mock接口
(3)获取是那么mock方法被调用了
(4)获取被mock之后的对象
mock PowerMock实战手册
Programming系列丛书
十、Mockingwithspies
这个spies单词比较奇怪,是间谍,密探等意思,但是放到这个应用场合我总觉得别扭,因为它的意思好像和在PowerMock中的使用场合不太一样,如果读者还有更好的翻译,发信息给我哈,好了我们来看看如何使用spies。(www.61k.com]
10.1、使用场景
经过了前面九个章节的学习,相信读者应该清楚了一点,如果某个对象是mock产生的,那么他什么都不会做,除非你对其做了when...thenReturn这样的操作,否则所mock的对象调用任何方法,什么都不会做的,如果您没有做过类似的测试,我们在这里一起来看看。
packagecom.wangwenjun.powermock.spy.resource;
importjava.io.BufferedWriter;
importjava.io.FileWriter;
importjava.io.IOException;
publicclassFileService{
publicvoidwrite(finalStringtext){
BufferedWriterbw=null;
try{
bw=newBufferedWriter(newFileWriter(
System.getProperty("user.dir")+"/wangwenjun.txt"));
bw.write(text);
bw.flush();
System.out.println("contentwritesuccessfully.");
}catch(IOExceptione){
e.printStackTrace();
}finally{
if(bw!=null)
try{
bw.close();
}catch(IOExceptione){
mock PowerMock实战手册
Programming系列丛书
//bequietly
}
}
}
}
上面的代码其实完全不可以用mock的方式来测试,但是为了说明我刚才的理论,我们来写一个测试用例来看一看。[www.61k.com)
packagecom.wangwenjun.powermock.spy.resource;
importorg.junit.Test;
importorg.powermock.api.mockito.PowerMockito;
publicclassFileServiceTest{
@Test
publicvoidtestWrite(){
FileServicefileService=PowerMockito.mock(FileService.class);fileService.write("liudehua");
}
}
运行上面的测试用例,你会发现根本没有生成一个wangwenjun.txt文件,也就意味着被mock的class是个彻头彻尾的假对象,什么都干不了的。
10.2、PowerMock测试
我们采用spy的方式mock一个对象,然后再调用其中的某个方法,他就会根据真实class的所提供的方法来调用,好了,我们再来写一个spy的测试@Test
publicvoidtestWriteSpy()
{
FileServicefileService=PowerMockito.spy(newFileService());fileService.write("liudehua");
Filefile=newFile(System.getProperty("user.dir")+"/wangwenjun.txt");
assertTrue(file.exists());
}
mock PowerMock实战手册
Programming系列丛书
运行上面的测试用例,你会发现生成了wangwenjun.txt文件,并且里面有liudehua字样。(www.61k.com]
10.3、何时使用Spy
Spy是一个特别有意思的API,他能让你mock一个对象,并且只mock个别方法的行为,保留对某些方法原始的业务逻辑,根据具体情况选择使用。
十一、Mockingprivatemethods
单纯就测试private修饰的方法而言,这个非常有争议,有人说测试private方法采用反射的方式会破坏class的封装性,有人说既然是单元测试需要面面俱到,在互联网上争论都是比较激烈的,那方都没有说服另外一方,我个人也是比较赞成不要通过反射的方式去测试一个私有方法,如果私有方法写得好,对调用处的代码写好单元测试就会完全覆盖私有方法的逻辑。
但是本章中所要体现出来的场景还真的需要去mock一个private方法,好了,来看看最后一个PowerMock的功能吧。
11.1、使用场景
假设我们有一个类,其中有一个方法A是公有方法,但是他需要依赖一个私有方法B,但是其中的方法B是一个很难在单元测试中真实模拟,所以我们需要mock私有方法的行为,好了我们同样看一看业务代码,然后再通过PowerMock的方式来进行一下测试
mock PowerMock实战手册
Programming系列丛书11.2、业务代码
packagecom.wangwenjun.powermock.mockprivate;
publicclassEmployeeService{
publicbooleanexist(StringuserName){
checkExist(userName);
returntrue;
}
privatevoidcheckExist(StringuserName){
thrownewUnsupportedOperationException();
}
}
11.3、PowerMock测试
上面的业务代码中我们发现如果要测试exist方法,肯定需要实现mock出来checkExist的行为,否则真的没有办法对exist进行测试。[www.61k.com)
packagecom.wangwenjun.powermock.mockprivate;
importstaticorg.junit.Assert.assertTrue;
importstaticorg.junit.Assert.fail;
import
import
import
import
importorg.junit.Test;org.junit.runner.RunWith;org.powermock.api.mockito.PowerMockito;org.powermock.core.classloader.annotations.PrepareForTest;org.powermock.modules.junit4.PowerMockRunner;
@RunWith(PowerMockRunner.class)
@PrepareForTest(EmployeeService.class)
publicclassEmployeeServiceTest{
@Test
publicvoidtestExist(){
try{
EmployeeServiceemployeeService=PowerMockito.spy(new
mock PowerMock实战手册
Programming系列丛书
扩展:powermock 实战 / powermock / powermockito
EmployeeService());
PowerMockito.doNothing().when(employeeService,"checkExist",
"wangwenjun");
booleanresult=employeeService.exist("wangwenjun");
assertTrue(result);
PowerMockito.verifyPrivate(employeeService).invoke("checkExist","wangwenjun");
}catch(Exceptione){
e.printStackTrace();
fail();
}
}
}
十二、总结
截至目前已经写了很多本电子书了,但是这一本写的非常仓促,而且也没有来得及进行审核,但是可以保证其中的代码都能运行通过,如果其中的一些例子运行有问题,可以发信息给我。[www.61k.com]
扩展:powermock 实战 / powermock / powermockito
二 : 健身房实战手册 45天立现“马甲线”
必须配合运动饮食双管齐下
建议初学者,一开始尽量挑选轻、中量级的入门款健身器材做锻炼,不要因为求好心切而伤了身体。(www.61k.com]到健身房运动,除了努力做腰腹器材运动,也必须配合心肺运动器材,饮食控制;才有可能达到1个半月~2个月立马的马甲线效果。
锻炼一下腹部运动
1.轻松站在下腹卷曲器上,保持身体的中心位置,准备好即开始。
2.身体直立,手部放轻松至于下腹卷曲机器上,脚呈45度准备开始往上抬。
3.持续身体中立,背部挺直,运用肚子的力量慢慢将脚再抬起45度。
注意事项:不宜使用脚部的力量,可能会造成骨盆前倾的问题。
骨盆一定保持中立,不要晃动或歪斜。切记不可以将力量放于脚部。
三 : 创业者战局:学成文武艺 卖给A和T?
以前,创投圈就流行一个段子。创业者找投资。投资人总会问:如果BAT也做你这个项目,你怎么办?创业者微微一笑反问道:BAT也做投资呢,你们怎么办?
《庞涓夜走马陵道》一开始就点明了古代人建功立业的路径:“学成文武艺,货与帝王家。帝王不用,卖与识家。识家不用,仗义行侠。”
到了中国的互联网创业圈里,这句话就被演绎成了:学成文武艺,卖给BAT(百度、阿里、腾讯)。
2010年,团购大热,还在KPCB(凯鹏华盈)的周炜跟吴波谈好了价格,要投资拉手网。结果,签约的前一天,被朱啸虎给截胡了。
周炜当时很沮丧,最后投资了当时的第四名,高朋网。
现在谈起这件事儿,周炜还有点儿小庆幸。相比当时的拉手、窝窝,高朋算是善始善终,最终卖给了腾讯。
2011年,腾讯3.25亿元投资高朋。
同年,腾讯还花6000美元投资了好乐买,8440万美元投资了艺龙。团购,电商,在线旅游,都是竞争残酷的市场,创业公司成批的出现又成批死去,这几家公司虽然没有最终的胜者,但创始人却都得以全身而退。
创业这件事,赚到了钱,就不能算输。
2010年到2013年,中概股经历着倒春寒。2010年12月,当当上市时,媒体纷纷羡慕,“李国庆套现2080万美元”。但到了,2012年3月,唯品会登陆纽交所时,已经变成了“流血上市”。
此时,已经上市的BAT(阿里B2B业务2007年在香港上市),手里有了现金储备,也有了投资并购的意识,开始投资并购一些创业公司。公开数据显示,2010年,阿里腾讯各自投资了大约10家公司。
市场上的风险投资还不像今天这样普遍,IPO之路又道阻且长。年轻的创业者,心里大抵有个暗暗的想法:把公司做到一定的规模,等被BAT收购后,就可以实现财富自由了。
到2014年年中,有一两百个公司因为BAT的收购而上岸。数据显示,腾讯自上市后花了537亿元并购了80家公司,其中的98%发生在2010年之后。
▲图片截自VC SaaS。
2
2014年前后,中国互联网领域迎来了一个收获的高潮。
不说阿里、京东这样巨大的造福运动——传言中,淘宝上市,造就一万多名千万富翁。单是聚美、陌陌等公司的刺激,也让创业者们激动不已。
2014年,聚美优品在纽交所IPO,陌陌登陆纳斯达克。这些成立仅仅三年多的公司,一上市,市值就接近30亿美元。而唯品会也在这一年 4 月市值超越 360,成为了中国第四大互联网上市公司。
这一年的福布斯中国富豪榜,40 under 40,也格外耀眼。前十名分别是京东刘强东,搜狗王小川,58姚劲波,人人贷管理团队(张适时、李欣贺、杨一夫)、猎豹傅盛,聚美陈欧,百度副总裁李明远,美团王兴,途牛于敦德,陌陌唐岩。
此外,还有大量的未上市独角兽在列,包括猎聘网戴科彬,触控陈昊芝,豌豆荚王俊煜,格瓦拉刘勇,优信戴琨,口袋购物王珂,美柚陈方毅等。
这些创业故事,刺激着更多的创业者,想要成为耀眼的明日之星。
而且,此时的风险投资大放光芒。按发行价,经纬投资猎豹回报约16倍,红杉投资聚美优品回报约144倍,塞富亚洲投资58同城回报约48倍,今日资本投资京东回报约121倍,软银中国投资阿里巴巴回报超过1000倍。
让更多的创业者和投资机构对未来充满信心,认为即使创业维艰,一样条条大路通罗马。
然后,三年多过去后,创业者们又不得不重新认清一个残酷的现实。大部分创业到最后,可能还是要卖给阿里和腾讯的(就连百度也已经远远落后于腾讯阿里了)。
2016年7月5日,阿里宣布全资收购豌豆荚,作价2亿美元。2亿美元听起来不少,但与最风光的时候相比,已经是泥车瓦狗。3年前,百度收购91无线的价格是19亿美元。
曾经因为捕鱼达人风光一时的触控,最终也只能在韩国通过子公司曲线上市。
就连曾经因为并购土豆网而风光一时的优酷也难逃被收编的命运,最终被阿里以56亿美元全资收购。优酷新掌门杨伟东说,现在优酷土豆不着急盈利了,也不怕投资(烧钱)了,因为背后有阿里的生态和资本。
还是2014年,打车战争爆发,滴滴最终成长为今天的出行小巨头。公开资料显示,滴滴前后融资约150亿美元(还不包括优步中国的融资)。然而,融资方中,除了软银、淡马锡、老虎基金等大型的国际投资机构外,还有一大部分资金来自苹果、腾讯、阿里巴巴等科技巨头。
今天,市场上打的最激烈的两家公司,ofo和摩拜,也变成了阿里和腾讯的。公开数据显示,阿里领投ofo的E轮7亿美元融资,腾讯领投了摩拜的E轮6亿美元融资。
A和T的资本已经无处不在,即使京东、美团点评、滴滴、58这样的小巨头也都不能独立在BAT之外。
360周鸿祎感慨说,“BAT太大之后,他们用了一种非常综合的手段,看到哪个小家伙有可能颠覆,有可能在自己不擅长的领域进去,他就去买下或者投资,滴滴和快的就变成两个巨头的脚力。”
3
创业者要不要站队,争议由来已经。
现在,创业者们也越来越早的意识到了这一点:要早站队。
“一定得站队,你不站队意味着你被抛弃了。” e家洁A轮的时候,创始人云涛就去找了腾讯和盛大的投资,目前,腾讯一直跟投到C轮。
云涛说,越高频的东西,越需要BAT的附加价值,像打车外卖,就是BAT之间的流量竞争。你想着,你要自己做,独立竞争,基本上没有这种机会了,因为你面临着支付等问题,逃不过BAT的基础设施。
车轮互联的吴峰,二次创业,公司每年有1亿元的流水,但是他觉得自己很焦虑。“你看外卖、打车这么激烈,我这个行业没有对手啊,BAT怎么不来找我呢?我是不是选错方向了?”去年,他拿到了C轮数亿元的融资,依旧因为投资不是来自BAT而少了一些激动。
云涛认为创业者该站队,是从流量入口的角度去看的。BAT在中国前二十年已经帮我们建了一个网络基础设施,所以,我们必须要跟他合作。
流量入口重不重要?
传说,马化腾跟滴滴谈B轮投资的时候,阿里出身的程维一直在犹豫,最终,马化腾是拿了微信的入口打动了他。
还是2014年,腾讯4亿美元投资点评,并且给了微信入口。看起来,点评在流量入口和资金储备上又占据了优势。但当时美团的王兴并没有太多的担心,他觉得,“微信是通信的入口,它可以承载很多东西,但我不认为它能承载所有的东西。”
“入口的作用越来越小,用户习惯的影响正在变大。”实际上,可能也是如此。36Kr最近的报道显示,摩拜仅有10%的流量来自微信。
但是,今天的创业者们,要面对的不仅仅是流量的问题,还有一个更重要的东西,叫做资本。
周炜感慨说,今天的互联网创业就是《三体》里的黑暗森林状态啊,降维攻击时常发生。所谓降维攻击,就是资本瞬间堆积到无限大,把市场上的资本全部抽走。
打车、外卖、共享单车,每一个做上风口的领域,无不在重复这种故事。
朱啸虎曾经感慨说,打车那一仗,让他意识到,千万不能让阿里腾讯站在对立面上打起来,一旦打起来太吓人了。
所以,投资ofo的时候,朱啸虎特地拉上了滴滴,心里想着滴滴同时有阿里和腾讯的投资。但是,他万万没想到,腾讯没有进入ofo后,转投了竞争对手摩拜。金沙江的另外一个投资人,罗斌感慨里面的阴差阳错,说如果腾讯投了ofo,真的是可以在90天之内结束战斗的。
▲图片截自VC SaaS。
4
互联网科技公司手里的现金越来越多。
今天,阿里、腾讯的市值都已经超过3000亿美元。7月15日的数据显示,阿里市值一度突破3850亿美元,腾讯也有3323亿美元。
腾讯、阿里不但有高现金流,还有高现金储备。腾讯2017年1季度财报显示,腾讯拥有现金净额275.72亿元,按40亿美元算,也超过了很多大型投资机构管理的资金规模。
凭借手里的资金,腾讯、阿里都在进一步加大了投资并购的力度。
一份来自分析机构的数据显示,2015年,腾讯投资数量接近110起,阿里也接近70起。2016年投资数量有所下降,腾讯90多起,阿里60多起,但是投资的数额却都进一步加大。
IT桔子显示,2016年,腾讯投资或收购的公司超过85起,涉及金额137亿美元。而阿里巴巴2016年投资并购超过55家,涉及金额155亿美元。
2016年的数据显示,经纬中国,大概管理着13亿美元的基金池。红杉中国风险基金六期规模5亿美元-5.5亿美,红杉中国成长基金四期规模为8.5亿-9亿美元。也就是说,阿里和腾讯一年投出了至少30支中大型风险投资基金的规模。
风险投资机构必须要看到一个事实,互联网科技巨头手里的现金储备已经远远超过了自己。
这不是中国特有的现象。
《经济学人》最新的一篇文章里显示,苹果、谷歌(Alphabet)、微软、亚马逊和Facebook,这五大科技巨头的总市值高达2.9万亿美元。他们不但市值节节攀升,而且持有的现金储备也达到了空前的规模,有3300亿美元之多。
分析师们预测,到2020年,这5大巨头的现金储备将达到6800亿美元。即使是早期一直因为亏损而遭受质疑的亚马逊,净现金储备也将达到500亿美元。
虽然,这些巨头在各种烧钱领域进行了大量的投资,比如人工智能、无人驾驶、云计算等。2014年,Facebook以190亿美元的价格收购了whatsapp。
但算上自己研发和投资并购,他们也只花掉了1000亿美元。大概是5年前的3倍。
他们根本就花不完。分析师们算了一下,如果要5大巨头把钱都花完,那么2020年还要花出3000亿美元。
据说,这是Netflix、优步、特斯拉这三家最缺钱的公司未来每年烧掉的51倍。也是这5大巨头现有投资并购规模的37倍。
而全球所有的风险投资机构,每年的投资金额加起来还不到1500亿美元,仅是这5大巨头净现金的一半。。
以前,创投圈就流行一个段子。
创业者找投资。投资人总会问:如果BAT也做你这个项目,你怎么办?
创业者微微一笑反问道:BAT也做投资呢,你们怎么办?
今天,他们都要好好的思考一下这个问题了——到底是卖给A,还是卖给T呢?
本文标题:创业者实战手册-PowerMock实战手册61阅读| 精彩专题| 最新文章| 热门文章| 苏ICP备13036349号-1