Java 單元測試簡單掃盲
前言
仔細回想起來,上次認真編寫單元測試已經是兩年前的事了。那時候覺得寫單元測試是種負擔。
為了應付代碼覆蓋率要求,常常依賴工具自動生成測試用例,有時需要啟動Spring容器,有時又不需要(當時還分不清單元測試和集成測試的區別)。
直到最近在開發過程中,當需要重構代碼或自測功能時,我才真正體會到單元測試的價值。
概念
單元測試的本質是通過獨立的測試用例來驗證代碼單元(方法/函數)的邏輯正確性。
在日常開發中,我們經常會在類里隨手寫一個 main 方法來快速驗證邏輯,比如:
public static void main(String[] args) {
int expectResult = 9;
int result = 3 * 3;
if (result == expectResult) {
System.out.println("測試成功");
} else {
System.out.println("測試失敗");
}
}
測試分類
首先介紹一下,單元測試與集成測試的區別,剛開始學習的時候,沒有分清它倆的區別,導致一直感覺單元測試是一個很復雜的東西。
集成測試
需要啟動完整的 Spring 容器,容器內所有的 Bean 可以正常注入使用。通俗一點,相當于寫了一個 TestController。
@SpringBootTest // 啟動完整Spring容器
class UserControllerIntegrationTest {
@Autowired // 真實注入Bean
private UserController userController;
@Test
void testGetUser() {
User user = userController.getUser(1L);
assertNotNull(user);
}
}
單元測試
不啟動 Spring 容器,所有依賴需要手動模擬
@ExtendWith(MockitoExtension.class) // 啟用Mockito注解支持
class UserServiceUnitTest {
@Mock
private UserRepository userRepository;
@InjectMocks
private UserService userService;
@Test
void testGetUser() {
when(userRepository.findById(1L))
.thenReturn(new User(1L, "Mock用戶"));
User user = userService.getUser(1L);
assertEquals("Mock用戶", user.getName());
}
}
| 維度 | 單元測試 | 集成測試 |
|---|---|---|
| 目標 | 驗證單個代碼單元(如方法、類)的功能正確性 | 驗證多個模塊、組件或外部系統協同工作的正確性 |
| 范圍 | 隔離測試,不依賴外部系統(如數據庫、網絡、其他服務) | 依賴外部系統或跨組件的交互(如數據庫連接、API 調用) |
| 覆蓋范圍 | 聚焦分支,驗證代碼片段邏輯正確性 | 聚焦模塊間交互,驗證系統整體行為 |
核心注解介紹
@Resource (Spring標準注解)
作用:用于依賴注入,會按照名稱或類型從Spring容器中獲取真實的bean
測試場景:集成測試中需要完全使用真實邏輯時
@MockBean (Spring Boot測試注解)
作用:向Spring應用上下文注入一個mock對象,替代原有的bean
測試場景:Spring Boot集成測試中需要mock某些bean時
@Spy (Mockito注解)
作用:創建部分mock對象,未mock的方法使用真實邏輯,mock的方法使用自定義邏輯
測試場景:需要保留對象大部分真實行為,僅修改少數方法邏輯的測試
@Mock (Mockito注解)
作用:創建完整mock對象,所有方法都需要mock,未mock的方法會返回默認值或空集合
測試場景:需要完全模擬依賴行為的單元測試
@InjectMocks (Mockito注解)
作用:自動將@Mock或@Spy創建的mock對象注入到被測試對象中
測試場景:需要自動裝配依賴的單元測試
使用
依賴文件
添加依賴,具體版本需要根據項目版本自己替換
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
單元測試
@Spy 與 @Mock 的區別:
@Mock 所有方法都需要 mock,未 mock 的方法會返回默認值或空集合 ; @Spy 未 mock 的方法使用真實邏輯,mock 的方法使用自定義邏輯

注意:沒有無參構造會初始化為空指針,需要手動實例化進行解決
@Spy
private UserService userService = new UserService(); // 顯式提供實例
集成測試
@MockBean:向Spring上下文注入 Mock對象
@SpringBootTest
public class UserServiceTest {
@Autowired
private UserService userService; // 注入真實 UserService
@MockBean
private UserRepository userRepository; // 替換 Spring 容器中的 UserRepository
@Test
public void testGetUser() {
User mockUser = new User(1, "Alice");
when(userRepository.findById(1)).thenReturn(Optional.of(mockUser));
User result = userService.getUser(1);
assertEquals("Alice", result.getName());
verify(userRepository).findById(1);
}
}
總結
更多的內容還需要在探索后補充
本文來自博客園,作者:帥氣的濤啊,轉載請注明原文鏈接:http://www.rzrgm.cn/handsometaoa/p/18835301

浙公網安備 33010602011771號