Mockito是一個Java單元測試框架,它允許開發者創建和配置模擬對象(mock objects),以便在隔離的環境中測試代碼,尤其是當實際對象難以構造或其行為不確定時。下面是一些核心的Mockito API及其使用場景和代碼示例。
基礎API
-
創建Mock對象
@Mock
注解或Mockito.mock(Class<T> classToMock)
方法用于創建mock對象。
場景: 當你需要模擬一個類的行為,以便測試依賴于它的類或方法時。
示例:
@Mock List<String> mockedList;// 或者 List<String> mockedList = Mockito.mock(List.class);
-
定義Mock行為
Mockito.when(mockedMethodCall).thenReturn(value)
定義當特定方法被調用時應返回的值。
場景: 你想要控制模擬對象在特定調用下的響應。
示例:
Mockito.when(mockedList.get(0)).thenReturn("first");
-
驗證交互
Mockito.verify(mockedObject).methodCall(arguments)
驗證某個方法是否按照預期被調用了。
場景: 驗證測試過程中mock對象的某個方法確實被正確調用。
示例:
mockedList.add("one"); Mockito.verify(mockedList).add("one");
-
捕獲參數
- 使用
ArgumentCaptor
捕獲傳遞給mock方法的參數,以便進一步檢查。
場景: 需要檢查方法調用的具體參數時。
示例:
ArgumentCaptor<String> argument = ArgumentCaptor.forClass(String.class); Mockito.verify(mockedList).add(argument.capture()); assertEquals("captured", argument.getValue());
- 使用
-
設置異常
Mockito.when(mockedMethodCall).thenThrow(exception)
用于模擬方法拋出異常。
場景: 測試代碼對異常的處理邏輯。
示例:
Mockito.when(mockedList.get(999)).thenThrow(new IndexOutOfBoundsException());
具體使用場景示例
假設你有一個UserService
類,它依賴于UserRepository
來獲取用戶信息。你想測試UserService
的getUserById
方法,但不希望真實地查詢數據庫。
public class UserService {private UserRepository userRepository;public UserService(UserRepository userRepository) {this.userRepository = userRepository;}public User getUserById(int id) {return userRepository.findById(id);}
}public interface UserRepository {User findById(int id);
}
測試類使用Mockito模擬UserRepository
:
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;class UserServiceTest {@MockUserRepository userRepository;private UserService userService;@BeforeEachvoid setUp() {userService = new UserService(userRepository);}@Testvoid getUserById_ReturnsUser() {// 創建模擬行為User mockUser = new User(1, "John Doe");when(userRepository.findById(1)).thenReturn(mockUser);// 調用待測試方法User result = userService.getUserById(1);// 驗證結果assertEquals(mockUser, result);// 驗證交互Mockito.verify(userRepository).findById(1);}
}
在這個例子中,UserRepository
被模擬,其findById
方法被設定為返回一個預設的User
對象,從而允許我們專注于測試UserService
的邏輯,而不必關心數據庫操作的細節。
當然,除了基本的Mock對象之外,Mockito還提供了Spy
功能,以及其他一些高級特性,以滿足更復雜的測試需求。下面我將繼續介紹這些內容。
Spy
Spy與Mock相似,但它會委托真實對象執行未被模擬的方法調用,只有被明確指定的方法才會被模擬。這在你需要大部分保留原有對象行為,僅修改或監控部分行為時非常有用。
API:
Mockito.spy(Object object)
創建一個Spy對象。
場景: 當你希望大部分情況下使用真實對象的行為,只在某些特定方法上進行模擬或驗證時。
示例:
public class Calculator {public int add(int a, int b) {return a + b;}public int subtract(int a, int b) {return a - b;}
}@Test
void testSpy() {Calculator realCalculator = new Calculator();Calculator spyCalculator = Mockito.spy(realCalculator);// 模擬add方法的行為when(spyCalculator.add(1, 1)).thenReturn(3);// 調用真實subtract方法int result = spyCalculator.subtract(5, 2);// 驗證add方法的模擬行為assertEquals(3, spyCalculator.add(1, 1));// 驗證subtract方法的調用及結果assertEquals(3, result);verify(spyCalculator).subtract(5, 2);
}
其他高級API
-
DoAnswer: 提供更靈活的方式來定義模擬方法的行為,可以基于回調函數執行自定義邏輯。
示例:
doAnswer(invocation -> {Object[] args = invocation.getArguments();return args[0] + args[1]; }).when(someMock).someMethod(anyInt(), anyInt());
-
BDD風格: Mockito提供了一套行為驅動開發(Behavior-Driven Development)風格的API,使得測試代碼更加可讀。
示例:
given(mockedList.get(0)).willReturn("first"); then(mockedList).should().add("one");
-
MockitoJUnitRunner: 使用這個Runner可以自動初始化使用
@Mock
或@Spy
注解的字段,無需在每個測試方法中手動初始化。示例:
@RunWith(MockitoJUnitRunner.class) public class MyTestClass {@MockList<String> mockedList;// 測試方法... }
-
MockitoAnnotations.openMocks(this): 如果不使用
MockitoJUnitRunner
,可以在測試類的setUp
方法中手動打開Mockito注解。示例:
@BeforeEach public void setUp() {MockitoAnnotations.openMocks(this); }
通過結合使用這些API,Mockito能夠幫助開發者編寫更加高效、精確的單元測試,確保代碼質量。
使用說明
具體使用說明和示例,你可以參考以下資源:
- 官方文檔: 訪問Mockito官方網站,查看最新的官方文檔,包括API參考和用戶指南。
- 在線教程: 網站如Stack Overflow上有大量關于Mockito使用的問答,涵蓋了從基礎到高級的各個方面。
- 技術博客: CSDN、博客園等技術社區有大量Mockito的教程和實踐分享,比如通過搜索“Mockito進階使用”、“Mockito詳盡教程”等關鍵詞。