PowerMockito的基本使用解析
powermockito经常会结合mockito使用,先说一下这2个的介绍:
1.mockito和powermockito的简介
mockito和powermockito是什么东西呢?他们有什么作用呢?
mocktio和powermockito都是mock的工具类,主要是java的类库,mock就是伪装的意思。
他们适用于单元测试中,对于单元测试来说,我们不希望依赖于第三方的组件,比如数据库、webservice等。在写单元测试的时候,我们如果遇到了这些需要依赖第三方的情况,我们可以使用mock的技术,伪造出来我们自己想要的结果。
对于java而言,mock的对象主要是java 方法和 java类。
下面我就介绍一下怎么使用mockito和powermockito去进行mock。
2.mockito和powermockito的区别
在我看来,powermockito是mockito的一种增强,他们的powermockito可以调用mockito的方法,但是对于mocktio不能mock的对象或者方法,我们可以使用powermockito来实现。
比如mockito不能用于static method, final method, 枚举类, private method,这些我们都可以用powermockito来实现,当powermockito和mockito结合使用的时候,我们需要考虑兼容性的问题。
两者的版本需要兼容
mockito | powermockito |
---|---|
2.8.9+ | 2.x |
2.8.0-2.8.9 | 1.7.x |
2.7.5 | 1.7.0rc4 |
2.4.0 | 1.7.0rc2 |
2.0.0-beta - 2.0.42-beta | 1.6.5-1.7.0rc |
1.10.8 - 1.10.x | 1.6.2 - 2.0 |
1.9.5-rc1 - 1.9.5 | 1.5.0 - 1.5.6 |
1.9.0-rc1 & 1.9.0 | 1.4.10 - 1.4.12 |
1.8.5 | 1.3.9 - 1.4.9 |
1.8.4 | 1.3.7 & 1.3.8 |
1.8.3 | 1.3.6 |
1.8.1 & 1.8.2 | 1.3.5 |
1.8 | 1.3 |
1.7 | 1.2.5 |
ref:https://github.com/powermock/powermock/wiki/mockito
3.具体用法
本文实现实现需要构造的接口和需要返回值的接口
引入依赖
<dependencies> <dependency> <groupid>org.projectlombok</groupid> <artifactid>lombok</artifactid> </dependency> <dependency> <groupid>org.springframework</groupid> <artifactid>spring-context-support</artifactid> </dependency> <dependency> <groupid>org.springframework</groupid> <artifactid>spring-test</artifactid> <scope>test</scope> </dependency> <dependency> <groupid>junit</groupid> <artifactid>junit</artifactid> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupid>org.mockito</groupid> <artifactid>mockito-all</artifactid> <version>2.0.2-beta</version> <scope>test</scope> </dependency> <dependency> <groupid>org.powermock</groupid> <artifactid>powermock-module-junit4</artifactid> <version>1.7.4</version> <scope>test</scope> </dependency> <dependency> <groupid>org.powermock</groupid> <artifactid>powermock-api-mockito</artifactid> <version>1.7.4</version> <scope>test</scope> </dependency> </dependencies>
需要mock的类:
processdb.java
package com.github.mock.simple.vo; public class processdb { public processdb(string ss){ system.out.println(ss + " enter processdb ..."); } public processdb(){ system.out.println("enter processdb ..."); } public void getresultofconnectdbnoreturn(string ss) { system.out.println(ss + " enter getresultofconnectdbnoreturn ..."); } public string getresultofconnectdb() { return "haha, really went to the database"; } }
需要测试的类:
iuserservice.java
package com.github.mock.simple.user; public interface iuserservice { public string testedmehtod(); }
userserviceimpl.java
package com.github.mock.simple.user.impl; import org.springframework.stereotype.service; import com.github.mock.simple.user.iuserservice; import com.github.mock.simple.vo.processdb; @service public class userserviceimpl implements iuserservice { @override public string testedmehtod(){ system.out.println("enter userserviceimpl testedmehtod ..."); processdb processdb = new processdb("bb"); processdb.getresultofconnectdbnoreturn("aa"); return processdb.getresultofconnectdb(); } }
bussinessservice.java
package com.github.mock.simple.user.impl; import com.github.mock.simple.vo.processdb; public class bussinessservice { public string testedmehtod() { system.out.println("enter bussinessservice testedmehtod ..."); processdb processdb = new processdb("bb"); processdb.getresultofconnectdbnoreturn("aa"); return processdb.getresultofconnectdb(); } }
测试类:
mockspringsimpletest.java
package com.github.mock.simple.test; import java.text.messageformat; import org.junit.assert; import org.junit.before; import org.junit.test; import org.junit.runner.runwith; import org.mockito.injectmocks; import org.mockito.mock; import org.mockito.mockitoannotations; import org.powermock.api.mockito.powermockito; import org.powermock.core.classloader.annotations.preparefortest; import org.powermock.modules.junit4.powermockrunner; import org.powermock.modules.junit4.powermockrunnerdelegate; import org.springframework.beans.factory.annotation.autowired; import org.springframework.test.context.contextconfiguration; import org.springframework.test.context.junit4.springjunit4classrunner; import com.github.mock.simple.user.iuserservice; import com.github.mock.simple.user.impl.bussinessservice; import com.github.mock.simple.user.impl.userserviceimpl; import com.github.mock.simple.vo.processdb; @runwith(powermockrunner.class) @powermockrunnerdelegate(springjunit4classrunner.class)//spring上下文 @preparefortest({bussinessservice.class,userserviceimpl.class}) @contextconfiguration(locations = {"classpath:applicationcontext-mock-inject.xml"}) public class mockspringsimpletest { //使用spring上下文 @autowired iuserservice userservice; @mock processdb processdb; //不使用spring上下文时,使用该注解 @injectmocks private bussinessservice bussinessservice; @before public void initmocks() throws exception { mockitoannotations.initmocks(this); //reflectiontestutils.setfield(userservice, "processdb", processdb); powermockito.whennew(processdb.class).witharguments("bb").thenreturn(processdb); // powermockito.whennew(processdb.class).withnoarguments().thenreturn(processdb); } @test public void mockconnectdb() { string aa = "haha, everything is fake"; powermockito.when(processdb.getresultofconnectdb()).thenreturn(aa); powermockito.donothing().when(processdb).getresultofconnectdbnoreturn("aa"); system.out.println(bussinessservice.testedmehtod()); assert.assertequals("haha, everything is fake", bussinessservice.testedmehtod()); } @test public void mockconnectdb2() { try { string aa = "haha, everything is fake"; powermockito.when(processdb.getresultofconnectdb()).thenreturn(aa); powermockito.donothing().when(processdb).getresultofconnectdbnoreturn("aa"); system.out.println(userservice.testedmehtod()); assert.assertequals("haha, everything is fake", userservice.testedmehtod()); } catch (exception ex) { system.out.println("--- getmessage ---"); system.out.println(ex.getmessage()); system.out.println(); system.out.println("--- tostring ---"); system.out.println(ex.tostring()); system.out.println(); // system.out.println("--- printstacktrace ---"); // stringwriter stringwriter = new stringwriter(); // printwriter printwriter = new printwriter(stringwriter); // ex.printstacktrace(printwriter); // system.out.println(stringwriter.tostring()); // system.out.println(); system.out.println("--- printstacktrace diy ---"); system.out.println(ex.getclass().getname() + ": " + ex.getmessage()); stringbuilder sbexception = new stringbuilder(); for (stacktraceelement ele : ex.getstacktrace()) { sbexception.append(messageformat.format("\tat {0}.{1}({2}:{3})\n", ele.getclassname(), ele.getmethodname(), ele.getfilename(), ele.getlinenumber()));; } system.out.println(sbexception); sbexception = null; // stringwriter = null; // printwriter = null; } } }
扫描注入xml
最后applicationcontext-mock-inject.xml
<?xml version="1.0" encoding="utf-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemalocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="com.github.mock.simple"/> </beans>
对于没有实现类,但又被依赖的接口,在applicationcontext-mock-inject.xml添加如下内容 (本文不需要):
<bean name="ixxservice" class="org.mockito.mockito" factory-method="mock"> <constructor-arg value="com.github.mock.simple.api.ixxservice"/> </bean>
同时在测试类里面添加下面的代码:
@mock ixxservice ixxservice;
在 @before里面添加下面的代码
reflectiontestutils.setfield(userservice, "ixxservice", ixxservice);
测试结果
powermockito的使用技巧
当it中有些依赖组件无法正常集成,需要mock支持测试,可以使用power mockito。
特别注意:
当对一个对象进行powermockito,应该在prepare方法,统一mock这个对象。然后在其他方法,分别进行调用when,否则,多个方法内进行mock,会出错。
比如有个 service处于it case的底层,普通的mock根本mock不进去,但我们又不能为了集成测试,为这个testcase单独开一个口子,注入mock对象。power mockito强大的mock能力在这里可以用上。
比如:
我的mock对象impalaservice它在schmamessagehandler类里new出来的,则需要加上注解。
首先在test 类的开头,加上注解头部,头部类是mock对象所在类。
@runwith(powermockrunner.class) @preparefortest({httpclient.class,schemamessagehandler.class})
其次:
pooledimpalaservice impalaservice = powermockito.mock(pooledimpalaservice.class); powermockito.whennew(pooledimpalaservice.class).witharguments((configurationanyobject()).thenreturn(impalaservice); donothing().when(impalaservice).createtable(anystring(),(schema) anyobject());
使用powermockito,注意在用any()参数时候,比如
donothing().when(impalaservice).createtable(anystring(),(schema) anyobject());
参数列表中,只要一个使用了any(),any****,则所有参数都要用any相关的参数,否则mock不成功。
总的来说,在it当中,只有你想mock一个对象,一定可以,比如你在a类中用到了b类,那么在preparefortest中增加a类的注解。
如下:
@preparefortest({a.class})然后,在it中 声明一个b类,b b = powermockito.mock(b.class);这时候,就可以指定b的方法的返回值,或 powermockit.donothing().when(b).方法名(),让该方法什么也不做。
最后,再讲a实例化。powermockit是讲究mock设置顺序的。一定要注意。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。
上一篇: 赵明“眼神杀”曝光荣耀Magic3真机:史无前例的相机组合!
下一篇: Mysql常用命令行大全