PowerMockito的基本使用解析
PowerMockito經(jīng)常會(huì)結(jié)合Mockito使用,先說(shuō)一下這2個(gè)的介紹:
1.Mockito和PowerMockito的簡(jiǎn)介
Mockito和PowerMockito是什么東西呢?他們有什么作用呢?
Mocktio和PowerMockito都是Mock的工具類(lèi),主要是Java的類(lèi)庫(kù),Mock就是偽裝的意思。
他們適用于單元測(cè)試中,對(duì)于單元測(cè)試來(lái)說(shuō),我們不希望依賴(lài)于第三方的組件,比如數(shù)據(jù)庫(kù)、Webservice等。在寫(xiě)單元測(cè)試的時(shí)候,我們?nèi)绻龅搅诉@些需要依賴(lài)第三方的情況,我們可以使用Mock的技術(shù),偽造出來(lái)我們自己想要的結(jié)果。
對(duì)于Java而言,mock的對(duì)象主要是Java 方法和 Java類(lèi)。
下面我就介紹一下怎么使用Mockito和PowerMockito去進(jìn)行Mock。
2.Mockito和PowerMockito的區(qū)別
在我看來(lái),PowerMockito是Mockito的一種增強(qiáng),他們的PowerMockito可以調(diào)用Mockito的方法,但是對(duì)于Mocktio不能Mock的對(duì)象或者方法,我們可以使用PowerMockito來(lái)實(shí)現(xiàn)。
比如Mockito不能用于static Method, final method, 枚舉類(lèi), private method,這些我們都可以用PowerMockito來(lái)實(shí)現(xiàn),當(dāng)PowerMockito和mockito結(jié)合使用的時(shí)候,我們需要考慮兼容性的問(wèn)題。
兩者的版本需要兼容
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.具體用法
本文實(shí)現(xiàn)實(shí)現(xiàn)需要構(gòu)造的接口和需要返回值的接口
引入依賴(lài)
<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的類(lèi):
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"; } }
需要測(cè)試的類(lèi):
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(); } }
測(cè)試類(lèi):
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上下文時(shí),使用該注解 @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>
對(duì)于沒(méi)有實(shí)現(xiàn)類(lèi),但又被依賴(lài)的接口,在applicationContext-mock-inject.xml添加如下內(nèi)容 (本文不需要):
<bean name="iXxService" class="org.mockito.Mockito" factory-method="mock"> <constructor-arg value="com.github.mock.simple.api.IXxService"/> </bean>
同時(shí)在測(cè)試類(lèi)里面添加下面的代碼:
@Mock iXxService iXxService;
在 @Before里面添加下面的代碼
ReflectionTestUtils.setField(userService, "iXxService", iXxService);
測(cè)試結(jié)果
PowerMockito的使用技巧
當(dāng)IT中有些依賴(lài)組件無(wú)法正常集成,需要mock支持測(cè)試,可以使用power mockito。
特別注意:
當(dāng)對(duì)一個(gè)對(duì)象進(jìn)行powermockito,應(yīng)該在prepare方法,統(tǒng)一mock這個(gè)對(duì)象。然后在其他方法,分別進(jìn)行調(diào)用when,否則,多個(gè)方法內(nèi)進(jìn)行mock,會(huì)出錯(cuò)。
比如有個(gè) Service處于IT case的底層,普通的mock根本mock不進(jìn)去,但我們又不能為了集成測(cè)試,為這個(gè)testcase單獨(dú)開(kāi)一個(gè)口子,注入mock對(duì)象。power mockito強(qiáng)大的mock能力在這里可以用上。
比如:
我的mock對(duì)象impalaService它在schmaMessagehandler類(lèi)里new出來(lái)的,則需要加上注解。
首先在test 類(lèi)的開(kāi)頭,加上注解頭部,頭部類(lèi)是mock對(duì)象所在類(lèi)。
@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()參數(shù)時(shí)候,比如
doNothing().when(impalaService).createTable(anyString(),(Schema) anyObject());
參數(shù)列表中,只要一個(gè)使用了any(),any****,則所有參數(shù)都要用any相關(guān)的參數(shù),否則mock不成功。
總的來(lái)說(shuō),在it當(dāng)中,只有你想mock一個(gè)對(duì)象,一定可以,比如你在A類(lèi)中用到了B類(lèi),那么在prepareForTest中增加A類(lèi)的注解。
如下:
@PrepareForTest({A.class})然后,在it中 聲明一個(gè)B類(lèi),B b = PowerMockito.mock(B.class);這時(shí)候,就可以指定b的方法的返回值,或 PowerMockit.doNothing().when(b).方法名(),讓該方法什么也不做。
最后,再講A實(shí)例化。PowerMockit是講究mock設(shè)置順序的。一定要注意。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
java 實(shí)現(xiàn)比較版本號(hào)功能
本篇文章主要介紹了java 中涉及到客戶端的系統(tǒng)經(jīng)常需要用到比較版本號(hào)的功能,并附小示例,希望能幫助需要的小伙伴2016-07-07Java 動(dòng)態(tài)代理的多種實(shí)現(xiàn)方式
動(dòng)態(tài)代理實(shí)際上是JVM在運(yùn)行期動(dòng)態(tài)創(chuàng)建class字節(jié)碼并加載的過(guò)程。本文講述了Java 動(dòng)態(tài)代理的多種實(shí)現(xiàn)方式,感興趣的朋友可以選擇適合自己的方式2021-06-06Mac中IntelliJ IDEA 2019.1注冊(cè)過(guò)程分享
這篇文章主要介紹了Mac中IntelliJ IDEA 2019.1注冊(cè)過(guò)程,本文給大家分享到腳本之家平臺(tái)供大家學(xué)習(xí),需要的朋友可以參考下2020-02-02Java實(shí)現(xiàn)幾種序列化方式總結(jié)
本篇文章主要介紹了Java實(shí)現(xiàn)幾種序列化方式總結(jié),包括Java原生以流的方法進(jìn)行的序列化、Json序列化、FastJson序列化、Protobuff序列化,有興趣的可以了解一下,2017-03-03解決SpringBoot2多線程無(wú)法注入的問(wèn)題
這篇文章主要介紹了解決SpringBoot2多線程無(wú)法注入的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-08-08SpringBoot?pdf打印及預(yù)覽(openhtmltopdf+freemarker)
這篇文章主要介紹了SpringBoot?pdf打印及預(yù)覽(openhtmltopdf+freemarker)2023-05-05Intellij IDEA實(shí)現(xiàn)springboot熱部署過(guò)程解析
這篇文章主要介紹了Intellij IDEA實(shí)現(xiàn)springboot熱部署過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08解決spring data jpa 批量保存更新的問(wèn)題
這篇文章主要介紹了解決spring data jpa 批量保存更新的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06教你如何精準(zhǔn)統(tǒng)計(jì)出你的接口"QPS"
今天小編就為大家分享一篇關(guān)于QPS的精準(zhǔn)計(jì)算方法,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2021-08-08