Mockito和PowerMock用法
一、mock測試和Mock對象
- mock對象就是在調(diào)試期間用來作為真實對象的替代品
- mock測試就是在測試過程中满钟,對那些不容易構(gòu)建的對象用一個虛擬對象來代替測試的方法就叫mock測試
二、Mockito和PowerMock
? PowerMock是Java開發(fā)中的一種Mock框架俯画,用于單元模塊測試拐纱。當你想要測試一個service接口,但service需要經(jīng)過防火墻訪問敦冬,防火墻不能為你打開或者你需要認證才能訪問。遇到這樣情況時唯沮,你可以在你能訪問的地方使用MockService替代脖旱,模擬實現(xiàn)獲取數(shù)據(jù)。
? PowerMock可以實現(xiàn)完成對private/static/final方法的Mock(模擬)介蛉,而Mockito可以對普通的方法進行Mock萌庆,如:public等。
三币旧、Mockito的使用
// 1践险、模擬HttpServletRequest對象,不需要依賴web容器吹菱,模擬獲得請求參數(shù)
HttpServletRequest request = mock(HttpServletRequest.class);
when(request.getParameter("foo")).thenReturn("boo");
// 注意:mock()是Mockito的靜態(tài)方法巍虫,可以用@mock注解替換
private @mock HttpServletRequest request
// 2、Person person =mock(Person.class);
// 第一次調(diào)用返回"xiaoming"毁葱,第二次調(diào)用返回"xiaohong"
when(person.getName()).thenReturn("xiaoming").thenReturn("xiaohong");
when(person.getName()).thenReturn("xiaoming", "xiaohong");
when(person.getName()).thenReturn("xiaoming");
when(person.getName()).thenReturn("xiaohong");
// 3垫言、mockito模擬測試無返回值的方法
Person person =mock(Person.class);
doNothing().when(person).remove();
// 4贰剥、mockito還能對被測試的方法強行拋出異常
Person person =mock(Person.class);
doThrow(new RuntimeException()).when(person).remove();
when(person.next()).thenThrow(new RuntimeException());
// 5倾剿、//UserAppService用于參數(shù)匹配器的demo
參數(shù)匹配器
UserApp app = new UserApp();
app.setAppKey("q1w2e3r4t5y6u7i8o9p0");
app.setAppSecret("q1w2e3r4t5y6u7i8o9p0");
when(userAppMapper.getAppSecretByAppKey(argThat(new ArgumentMatcher<String>() {
@Override
public boolean matches(Object argument) {
String arg = (String) argument;
if (arg.equals("1234567890") || arg.equals("q1w2e3r4t5y6u7i8o9p0")) {
return true;
} else {
throw new RuntimeException();
}
}
}))).thenReturn(app);
// 6、Answer接口模擬根據(jù)參數(shù)返回不同結(jié)果
when(userAppMapper.getAppSecretByAppKey(anyString())).thenAnswer(
(InvocationOnMock invocationOnMock) -> {
String arg = (String) invocationOnMock.getArguments()[0];
if (null == arg || arg.equals(null)) {
return null;
} else if (arg.equals("q1w2e3r4t5y6u7i8o9p0")) {
UserApp app = new UserApp();
app.setAppKey("q1w2e3r4t5y6u7i8o9p0");
app.setAppSecret("q1w2e3r4t5y6u7i8o9p0");
return app;
} else {
return null;
}
});
// 7蚌成、Mock對象是能調(diào)用模擬方法前痘,調(diào)用不了它真實的方法,但是spy() 或者@spy 可以監(jiān)視一個真實的對象担忧,對它進行方法調(diào)用時它將調(diào)用真實的方法芹缔,同時也可以設(shè)定這個對象的方法讓它返回我們的期望值。同時瓶盛,我們也可以用verify進行驗證最欠。
class A {
public void goHome() {
System.out.println("I say go go go!!");
return true;
}
}
// 當需要整體Mock示罗,只有少部分方法執(zhí)行真正部分時,選用這種方式
A mockA = Mockito.mock(A.class);
Mockito.doCallRealMethod().when(mockA).goHome();
// 當需要整體執(zhí)行真正部分芝硬,只有少部分方法執(zhí)行mock蚜点,選用這種方式
A spyA = Mockito.spy(new A());
Mockito.when(spyA.goHome()).thenReturn(false);
Demo演示
//目標測試類
@Service
public class UserAppService {
@Autowired
private UserAppMapper userAppMapper;
/**
* 通過appKey查詢AppSecre
* @return
*/
public String getAppSecretByAppKey(String appKey){
if (StringUtils.isEmpty(appKey)) {
return null;
}
UserApp userApp = userAppMapper.getAppSecretByAppKey(appKey);
if (null == userApp) {
return null;
}
return userApp.getAppSecret();
}
}
@RunWith(SpringJUnit4ClassRunner.class)
public class UserAppServiceTest {
@InjectMocks //創(chuàng)建一個實例,其余用@Mock(或@Spy)注解創(chuàng)建的mock將被注入到用該實例中
private UserAppService userAppService;
@Mock
private UserAppMapper userAppMapper;
@Before
public void setUp() { MockitoAnnotations.initMocks(this); }//初始化Mock對象
@Test
public void getAppSecretByAppKey3() throws Exception {
when(userAppMapper.getAppSecretByAppKey(anyString())).thenAnswer(
(InvocationOnMock invocationOnMock) -> {
String arg = (String) invocationOnMock.getArguments()[0];
if (null == arg || arg.equals(null)) {
return null;
} else if (arg.equals("q1w2e3r4t5y6u7i8o9p0")) {
UserApp app = new UserApp();
app.setAppKey("q1w2e3r4t5y6u7i8o9p0");
app.setAppSecret("q1w2e3r4t5y6u7i8o9p0");
return app;
} else {
return null;
}
});
assertEquals(userAppService.getAppSecretByAppKey("q1w2e3r4t5y6u7i8o9p0"), "q1w2e3r4t5y6u7i8o9p0");
assertEquals(userAppService.getAppSecretByAppKey("123456789"), null);
assertEquals(userAppService.getAppSecretByAppKey(null), null);
verify(userAppMapper, only()).getAppSecretByAppKey(anyString());
}
// 注意:verify記錄著這個模擬對象調(diào)用了什么方法拌阴,調(diào)用了多少次绍绘,never() 沒有被調(diào)用,相當于 times(0)迟赃,atLeast(N) 至少被調(diào)用 N 次陪拘,atLeastOnce() 相當于 atLeast(1),atMost(N) 最多被調(diào)用 N 次
// 參數(shù)匹配也可以為:verify(mock).someMethod(anyInt(), anyString());
四纤壁、PowerMock的使用
PowerMock基于Mockito開發(fā)左刽,起語法規(guī)則與Mockito一致,主要區(qū)別在于使用方面酌媒,以實現(xiàn)完成對private/static/final等方法(也支持mock的對象是在方法內(nèi)部new出來的)的Mock(模擬)悠反。具體事例如下:
1、添加依賴
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>objenesis</artifactId>
<groupId>org.objenesis</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
//2馍佑、 PowerMock有兩個重要的注解:
–@RunWith(PowerMockRunner.class)
–@PrepareForTest( { YourClassWithEgStaticMethod.class })
// 如果你的測試用例里沒有使用注解@PrepareForTest斋否,那么可以不用加注解@RunWith(PowerMockRunner.class),反之亦然拭荤。當你需要使用PowerMock強大功能(Mock靜態(tài)茵臭、final、私有方法等)的時候舅世,就需要加注解@PrepareForTest旦委。
//測試類
public class ClassUnderTest {
public boolean callArgumentInstance(File file) {
return file.exists();
}
public boolean callFinalMethod(ClassDependency refer) {
return refer.isAlive();
}
public boolean callStaticMethod() {
return ClassDependency.isExist();
}
public boolean callPrivateMethod() {
return ClassDependency.delete();
}
}
//依賴類
public class ClassDependency {
public static boolean isExist() {
return false;
}
public final boolean isAlive() {
return false;
}
priavte final boolean delete() {
return false;
}
}
// 2、Mock方法內(nèi)部new出來的對象
public void testCallInternalInstance() throws Exception {
File file = PowerMockito.mock(File.class);
ClassUnderTest underTest = new ClassUnderTest();
PowerMockito.whenNew(File.class).withArguments("bbb").thenReturn(file);
PowerMockito.when(underTest.callArgumentInstance( new File("bbb"))).thenReturn(true);
PowerMockito.when(file.exists()).thenReturn(true);
Assert.assertTrue(file.exists();
}
// 3雏亚、Mock普通對象的final方法
public void testCallFinalMethod() {
ClassDependency depencency = PowerMockito.mock(ClassDependency.class);
ClassUnderTest underTest = new ClassUnderTest();
PowerMockito.when(depencency.isAlive()).thenReturn(true);
Assert.assertTrue(underTest.callFinalMethod(depencency));
}
// 4缨硝、Mock靜態(tài)方法
public void testCallStaticMethod() {
ClassUnderTest underTest = new ClassUnderTest();
PowerMockito.mockStatic(ClassDependency.class);
PowerMockito.when(ClassDependency.isExist()).thenReturn(true);
Assert.assertTrue(underTest.callStaticMethod());
}
// 5、Mock私有方法
public void testCallPrivateMethod() throws Exception {
ClassUnderTest underTest = PowerMockito.mock(ClassUnderTest.class);
PowerMockito.when(underTest,"callPrivateMethod").thenCallRealMethod();
Assert.assertTrue(underTest.callPrivateMethod());
}