相關歷史文章(閱讀本文前,您可能需要先看下之前的系列👇)
國內最全的Spring Boot系列之三
2020上半年發文匯總「值得收藏」
SpringBoot框架開發的優秀的項目「值得收藏學習」 - 第335
Mock工具之Mockito - 第337篇
Spring Boot中使用Mockito - 第338篇
Spring Boot中使用Mockito進行Web測試 - 第339篇
Mockito中捕獲mock對象方法的調用參數[SpringBoot]
SpringBoot使用Mockito mock靜態方法/私有方法 - 第341篇
悟纖:師傅,我最近發現一個傢伙,特別厲害。
師傅:是不是發現了新大陸了。
悟纖:嗯,我最近看到一個更牛逼的傢伙Poowermockito增強了mockito的能力。
師傅:那徒兒和為師分享一下你學習的心得唄。
悟纖:那徒兒就獻醜了。
一、Mockito和PowerMock的簡介
Mocktio和PowerMock都是Mock的工具類,主要是Java的類庫,Mock就是偽裝的意思。他們適用於單元測試中,對於單元測試來說,我們不希望依賴於第三方的組件,比如資料庫、Webservice等。在寫單元測試的時候,我們如果遇到了這些需要依賴第三方的情況,我們可以使用mock的技術,偽造出來我們自己想要的結果。對於Java而言,mock的對象主要是Java 方法和Java類。
二、Mockito和PowerMock的區別
PowerMock是Mockito的一種增強,PowerMock可以調用Mockito的方法,但是對於Mocktio不能Mock的對象或者方法,我們可以使用PowerMock來實現。比如Mockito不能用於static Method, final method, 枚舉類, private method,這些我們都可以用powermock來實現,當然對於新版的Mockito配合上mockito-inline能解決部分的問題,這個具體看前面的章節《SpringBoot使用Mockito mock靜態方法/私有方法》。
二、Mockito和PowerMock版本對應關係
Mockito
PowerMock
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
三、PowerMock的使用
3.1 單元測試類上的註解說明
在 Spring Boot 的測試套件中,需要添加@RunWith(SpringRunner.class) 和 @SpringBootTest 註解。
但是 PowerMock 需要添加@RunWith(PowerMockRunner.class) 註解。@RunWith 註解只能有一個,解決方案是使用 @PowerMockRunnerDelegate 註解,同時使用@PowerMockIgnore 註解避免報錯:
@SpringBootTest
@RunWith(PowerMockRunner.class)@PowerMockRunnerDelegate(SpringRunner.class)@PowerMockIgnore({"javax.management.*", "javax.net.ssl.*"})
@PrepareForTest({UserController.class})public class TestStaticMethod {}3.2 mock靜態方法
靜態代碼的編寫和前面章節的《SpringBoot使用Mockito mock靜態方法/私有方法》是一樣的,這裡不重複編寫了,主要來看下具體的mock代碼編寫的區別:
@Beforepublic void setUp() { PowerMockito.mockStatic(UserController.class); PowerMockito.when(UserController.isTrue(any(String.class))).thenReturn(true);}
@Testpublic void verifyStaticMock() { boolean flag = userController.verifyStaticMcok(""); Assert.assertTrue(flag);}3.3 mock私有方法
我能在UserController添加一個私有方法:
@GetMapping(value = "/verifyPrivateMethod")public String verifyPrivateMethod(String userName) { System.out.println("傳入的用戶名:" + userName); String result = getUserName(userName); return result;}
private String getUserName(String str) { System.out.println("進入了私有方法" + str); return str;}看下我們的mock代碼:
@Testpublic void verifyPrivateMethod() throws Exception { UserController spy = PowerMockito.spy(userController); PowerMockito.when(spy, "getUserName", "zhangsan").thenReturn("lisi"); String userName = spy.verifyPrivateMethod("zhangsan"); PowerMockito.verifyPrivate(spy, Mockito.times(1)).invoke("getUserName", "zhangsan"); Assert.assertEquals("lisi", userName);}最後提供一下整個測試類:
package com.kfit.springbootmockitodemo;
import com.kfit.springbootmockitodemo.demo.controller.UserController;import org.junit.Assert;import org.junit.Before;import org.junit.Test;import org.junit.runner.RunWith;import org.mockito.Mockito;import org.powermock.api.mockito.PowerMockito;import org.powermock.core.classloader.annotations.PowerMockIgnore;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.boot.test.context.SpringBootTest;import org.springframework.test.context.junit4.SpringRunner;
import static org.mockito.Mockito.*;@SpringBootTest
@RunWith(PowerMockRunner.class)@PowerMockRunnerDelegate(SpringRunner.class)@PowerMockIgnore({"javax.management.*", "javax.net.ssl.*"})
@PrepareForTest({UserController.class})public class TestStaticMethod {
@Autowired private UserController userController;
@Before public void setUp() { PowerMockito.mockStatic(UserController.class); PowerMockito.when(UserController.isTrue(any(String.class))).thenReturn(true); }
@Test public void verifyStaticMock() { boolean flag = userController.verifyStaticMcok(""); Assert.assertTrue(flag); }
@Test public void verifyPrivateMethod() throws Exception { UserController spy = PowerMockito.spy(userController); PowerMockito.when(spy, "getUserName", "zhangsan").thenReturn("lisi"); String userName = spy.verifyPrivateMethod("zhangsan"); PowerMockito.verifyPrivate(spy, Mockito.times(1)).invoke("getUserName", "zhangsan"); Assert.assertEquals("lisi", userName); }
}四、總結
為什麼mockito不能mock靜態方法(mockito-inline為什麼可以呢)?mockito使用繼承的方式實現mock的,用CGLIB生成mock對象代替真實的對象進行執行,為了mock實例的方法,你可以在子類中覆蓋它,而static方法是不能被子類覆蓋的,所以mockito不能mock靜態方法。但powermock可以mock靜態方法,因為它直接在字節碼上工作。
我就是我,是顏色不一樣的煙火。
我就是我,是與眾不同的小蘋果。à悟空學院:https://t.cn/Rg3fKJD
學院中有Spring Boot相關的課程!點擊「閱讀原文」進行查看!
SpringBoot視頻:http://t.cn/A6ZagYTi
SpringBoot交流平臺:https://t.cn/R3QDhU0
SpringSecurity5.0視頻:http://t.cn/A6ZadMBe
ShardingJDBC分庫分表:http://t.cn/A6ZarrqS
分布式事務解決方案:http://t.cn/A6ZaBnIr
JVM內存模型調優實戰:http://t.cn/A6wWMVqG
Spring入門到精通:https://t.cn/A6bFcDh4
大話設計模式之愛你:https://dwz.cn/wqO0MAy7