背景
基礎知識
mockito單元測試:它的做法是mock掉目前類的所有外部依賴,保障自己的代碼沒有問題。舉個例子,如果資料庫查詢的語句出了問題,單元測試不會測試出來。因為它直接mock掉了,不會去真的去查資料庫。從這點來說,好像有點說不過去。但是吧,僅從代碼的角度來說,又好像并沒有什麼問題。因為它目标是保障自己的代碼正常,sql不算。再說除了單元測試,還測試用例不是。
編寫單元測試的流程:寫單元測試的時候,需要逐行分析代碼。如果是外部依賴,那麼mock掉它,自己模拟一個結果作為替代。否則繼續分析下一行,直到代碼結束。最後校驗在指定的輸入下,輸出的結果是否符合預期。
為什麼需要mock目前類的私有方法?
首先,當我們自動生成單元測試類的時候,它隻會為我們建立公共方法的測試方法。
當被測試類的一個公共方法調用它的私有方法時,單元測試就需要為私有方法裡面的内容,也進行逐行分析mock。特别的,如果有另一個公共方法也調用了這個私有方法,那個這個公共方法也需要做同樣的事情。明顯,從測試覆寫來說,這個私有方法已經被覆寫,沒必要再逐行mock一次。這時候,如果能mock掉這個私有方法就好了,對吧!
舉個例子
建立被測試類
調用的私有方法分為“有傳回”和“沒有傳回”兩種。分别建立了pubFunction1調用帶傳回的私有方法,pubFunction2調用不帶傳回的私有方法。
package com.aliyu.service.demo.mock;
/**
* 描述:單元測試如何mock目前類的其他私有方法調用
* <p>作者: aliyu
* <p>建立時間: 2023-01-10 10:57 下午
*/
public class MockitoDemo {
/**
* 模拟一個公共方法調用"不帶傳回"的私有方法
*/
public void pubFunction1(){
System.out.println("開始調用公共方法");
withoutReturn();
System.out.println("結束調用公共方法");
}
/**
* 模拟一個公共方法調用"帶傳回"的私有方法
*/
public void pubFunction2(){
System.out.println("開始調用公共方法");
withReturn();
System.out.println("結束調用公共方法");
}
private void withoutReturn(){
System.out.println("調用了'不帶'傳回的私有方法");
}
private String withReturn(){
System.out.println("調用了'帶'傳回的私有方法");
return "AAA";
}
}
建立測試類
不帶傳回的私有方法mock
注:還需要注意的是,必須是junit4,否則會報錯。在後面會提到。
完整代碼如下:
package com.aliyu.service.demo.mock;
import org.junit.Test;
import org.junit.jupiter.api.BeforeEach;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
/**
* 描述:單元測試如何mock目前類的其他私有方法調用
* <p>作者: aliyu
* <p>建立時間: 2023-01-11 1:40 上午
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest(MockitoDemo.class)
public class MockitoDemoTest {
@InjectMocks
private MockitoDemo mockitoDemo;
@BeforeEach
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
/**
* 測試公共方法調用不帶傳回的私有方法
* doNothing實作(暫不清楚和doAnswer的差別,傾向于使用doNothing)
*/
@Test
public void testPubFunction1() {
MockitoDemo mockitoDemo1 = PowerMockito.spy(mockitoDemo);
try {
PowerMockito.doNothing().when(mockitoDemo1,"withoutReturn");
} catch (Exception e) {
e.printStackTrace();
}
mockitoDemo1.pubFunction1();
}
/**
* 測試公共方法調用不帶傳回的私有方法
* doAnswer實作
*/
@Test
public void testPubFunction3() {
MockitoDemo mockitoDemo1 = PowerMockito.spy(mockitoDemo);
try{
Answer answer=new Answer(){
public Object answer(InvocationOnMock invocationOnMock) throws Throwable{
return null;
}
};
PowerMockito.doAnswer(answer).when(mockitoDemo1,"withoutReturn");
}catch(Exception e){
e.printStackTrace();
}
mockitoDemo1.pubFunction1();
}
}
執行檢視結果:
注:可以看到沒有輸出"調用了’不帶’傳回的私有方法"字樣,說明已經成功mock。
帶傳回的私有方法mock
與不帶傳回的私有方法差别隻在于mock時用的方法。
執行檢視結果:
注:可以看到沒有輸出"調用了’帶’傳回的私有方法"字樣,說明已經成功mock。
其他
如果用不是junit4,而是junit5會報錯
大緻的意思就是公有方法沒有傳回值,不能打一個有傳回值的樁。明明我是為有傳回的私有方法打樁的咧。
帶傳回值時doReturn必須在前面,否則mock失敗
注:就好像如果不行doReturn聲明傳回值的話,它就會先去執行一下私有方法。。