Mock有模仿、偽造的含義。Mock測試就是在測試過程中,對於某些不容易構造或者不容易獲取的物件,用一個虛擬的物件來建立以便測試的測試方法。mock工具使用範疇:
MockIto和PowerMock是眾多Mock框架中的兩種,類似的還有:JMock,EasyMock,大多 Java Mock 庫如 EasyMock 或 JMock 都是 expect-run-verify (期望-執行-驗證)方式,而 Mockito 則使用更簡單,更直觀的方法:在執行後的互動中提問。使用 Mockito,你可以驗證任何你想要的。而那些使用 expect-run-verify 方式的庫,你常常被迫檢視無關的互動。非 expect-run-verify 方式 也意味著,Mockito無需準備昂貴的前期啟動。他們的目標是透明的,讓開發人員專注於測試選定的行為。
我們在寫單元測試時,總會遇到類似這些問題:
1. 構造的入參,對於極值、異常邊界場景不好復現,相關的邏輯測不到,只能依靠測試環境或預發跑,運氣不好可能要改好幾次程式碼重啟機器驗證,費時費力;
2. 依賴別人介面,可能需要別人協助測試環境資料庫插數才能跑通;
3. 依賴的別人的介面還沒有開發完,為了不影響提測,如何完成單元測試?
4. 編寫的單元測試依賴測試資料庫的資料,每次跑都要資料庫改數?
5. 對service層加了邏輯,跑單元測試本地驗證的時候,由於種種原因,本地環境跑不起來,折騰半天跑起來驗證完了,下次開發需求又遇到了另一個問題本地環境啟動報錯???
6. 我就想dubug到某一行程式碼,但是邏輯複雜,東拼西湊的引數就是走不到,自己看程式碼邏輯還要去問別人介面的返回值邏輯??(未完待續……)引入Mockito和PowerMock使得編寫單元測試更輕鬆,更省時,更省力。
簡單說就是無論誰的本地環境,無論判斷條件多麼苛刻,無論本地資料庫的測試資料被誰刪了改了,無論別人介面的返回值邏輯多複雜,無論自己程式碼邏輯多複雜,都能獨立的、可重複執行的、行級別覆蓋的單元測試用例。
一句話說Mockito和PowerMock。當所測邏輯裡有靜態工具類方法或私有方法我們希望他返回特定值時(極值邊界、異常測試場景),我們要用到PowerMock去彌補Mockito的不足,除此之外,用Mockito去寫單測能完成我們日常任務95%的場景。
打樁:
when(XXxService.xxMethod("期望入參")).thenReturn("期望出參"); 驗證:verify(XXxService).xxMethod("期望入參");
import X;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.MockitoAnnotations;
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;
/**
* 測試類A,呼叫服務B和一個靜態工具類X
*/
@RunWith(PowerMockRunner.class)
@SpringBootTest(classes = {
A.class
})
@PowerMockIgnore({"javax.management.*"})
@PrepareForTest({X.class}) //mock 靜態方法
public class ATest {
@InjectMocks
private A a;
@Mock
private B b;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
@Test
public void Test() {
when(b.someMethodB(any())).thenReturn(someThingB());
a.someMethodA(someThingA1(), someThingA2());
verify(b).someMethodB(any());
}
/**
* 異常邊界測試
*/
@Test
public void test_ExceptionTest() throws ParseException {
PowerMockito.mockStatic(X.class);
// 模擬異常丟擲的場景
when(X.strToDate(anyString(), anyString())).thenThrow(ParseException.class);
when(X.convertLocalDateTime(any())).thenReturn(someThing());
when(b.someMethodB(any())).thenReturn(someThingB());
a.someThingA(someThingA1(), someThingA2());
verify(b).someMethodB(any());
}
優雅的mock可以考慮@spy,當然,mockito還有一些特性可以自行學習如:
文章寫於早些時候,目前有些較新技術湧入,如:Spock、TestableMock等,但上述技術依然適用於大型系統質量內建,讀者可根據自身情況選擇性選用。