PowerMockito的基本使用解析
PowerMockito經(jīng)常會結(jié)合Mockito使用,先說一下這2個的介紹:
1.Mockito和PowerMockito的簡介
Mockito和PowerMockito是什么東西呢?他們有什么作用呢?
Mocktio和PowerMockito都是Mock的工具類,主要是Java的類庫,Mock就是偽裝的意思。
他們適用于單元測試中,對于單元測試來說,我們不希望依賴于第三方的組件,比如數(shù)據(jù)庫、Webservice等。在寫單元測試的時候,我們?nèi)绻龅搅诉@些需要依賴第三方的情況,我們可以使用Mock的技術(shù),偽造出來我們自己想要的結(jié)果。
對于Java而言,mock的對象主要是Java 方法和 Java類。
下面我就介紹一下怎么使用Mockito和PowerMockito去進行Mock。
2.Mockito和PowerMockito的區(qū)別
在我看來,PowerMockito是Mockito的一種增強,他們的PowerMockito可以調(diào)用Mockito的方法,但是對于Mocktio不能Mock的對象或者方法,我們可以使用PowerMockito來實現(xiàn)。
比如Mockito不能用于static Method, final method, 枚舉類, private method,這些我們都可以用PowerMockito來實現(xiàn),當(dāng)PowerMockito和mockito結(jié)合使用的時候,我們需要考慮兼容性的問題。
兩者的版本需要兼容
| 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.具體用法
本文實現(xiàn)實現(xiàn)需要構(gòu)造的接口和需要返回值的接口
引入依賴
<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>
對于沒有實現(xiàn)類,但又被依賴的接口,在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>
同時在測試類里面添加下面的代碼:
@Mock iXxService iXxService;
在 @Before里面添加下面的代碼
ReflectionTestUtils.setField(userService, "iXxService", iXxService);
測試結(jié)果


PowerMockito的使用技巧
當(dāng)IT中有些依賴組件無法正常集成,需要mock支持測試,可以使用power mockito。
特別注意:
當(dāng)對一個對象進行powermockito,應(yīng)該在prepare方法,統(tǒng)一mock這個對象。然后在其他方法,分別進行調(diào)用when,否則,多個方法內(nèi)進行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()參數(shù)時候,比如
doNothing().when(impalaService).createTable(anyString(),(Schema) anyObject());
參數(shù)列表中,只要一個使用了any(),any****,則所有參數(shù)都要用any相關(guān)的參數(shù),否則mock不成功。
總的來說,在it當(dāng)中,只有你想mock一個對象,一定可以,比如你在A類中用到了B類,那么在prepareForTest中增加A類的注解。
如下:
@PrepareForTest({A.class})然后,在it中 聲明一個B類,B b = PowerMockito.mock(B.class);這時候,就可以指定b的方法的返回值,或 PowerMockit.doNothing().when(b).方法名(),讓該方法什么也不做。
最后,再講A實例化。PowerMockit是講究mock設(shè)置順序的。一定要注意。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Mac中IntelliJ IDEA 2019.1注冊過程分享
這篇文章主要介紹了Mac中IntelliJ IDEA 2019.1注冊過程,本文給大家分享到腳本之家平臺供大家學(xué)習(xí),需要的朋友可以參考下2020-02-02
SpringBoot?pdf打印及預(yù)覽(openhtmltopdf+freemarker)
這篇文章主要介紹了SpringBoot?pdf打印及預(yù)覽(openhtmltopdf+freemarker)2023-05-05
Intellij IDEA實現(xiàn)springboot熱部署過程解析
這篇文章主要介紹了Intellij IDEA實現(xiàn)springboot熱部署過程解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-08-08
教你如何精準(zhǔn)統(tǒng)計出你的接口"QPS"
今天小編就為大家分享一篇關(guān)于QPS的精準(zhǔn)計算方法,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2021-08-08

