簡介
測試通常分為三個階段:
1. Unit Test:確保程式的執行符合預期
2. 系統整合測試(SIT,System integration testing):確保系統各模組的交互沒有問題
3. 使用者驗收測試(UAT,User Acceptance Testing):確保符合用戶的需求與期望
單元測試是品質管理的一部份
一般來說交付的程式必須包含 Unit Test 程式碼
原則
– 最小測試單位
– 一個測試案例只測一個 Function
– 一個輸入對應一個輸出,不會有判斷
– 不同 input 就是不同 test case
– 一個 Function 若有多種邏輯判斷,則分別對應一個測試
– 無相依性
– 允許斷網
– 不會與其他測試案例交互
– 有修改就要重測
3A法則:Arrange → Act → Assert
mock
– 模擬外部回傳資料
– 關注點分離
使用
- 使用套件
spring-boot-starter-test
已包含 junit 與 mockito - 建立測試 Class
滑鼠右鍵 → Generate… → Test…
test 資料夾下會建立與 main 資料夾對應的目錄與類別 - 註解
@ExtendWith(MockitoExtension.class)
註解在測試類別上@Mock
註解在假資料上@InjectMocks
註解在要注入假資料的物件@Test
註解在方法上
- 撰寫測試方法
- 設定假資料的操作行為
when().thenReturn(); when().thenThrow();
- 如果參數不重要,會搭配以下方法,傳入符合型別的資料即可
any(); anyString(); anyByte(); anyBoolean(); anyChar(); anyCollection(); anyDouble(); anyFloat(); anyInt(); anyIterable(); anyList(); anyLong(); anyMap(); anySet(); anyShort();
- 檢核運行結果
org.junit.jupiter.api.Assertions
assertTrue(result); assertFalse(result); assertNull(result); assertNotNull(result); assertSame(a, b); // a == b assertNotSame(a, b); // a != b assertEquals(a, b); assertNotEquals(a, b); assertArrayEquals(a, b); assertIterableEquals(a, b); assertThrows(Exception.class, () -> {}); // Class.isInstance() assertThrowsExactly(Exception.class, () -> {}); assertDoesNotThrow(() -> {}); assertTimeout(Duration.ofSeconds(5), () -> {}); // 等待全部執行完畢 assertTimeoutPreemptively(Duration.ofSeconds(5), () -> {}); // 一超時馬上失敗
- 設定假資料的操作行為
- 執行程式
- Run method
- Run class 會執行類別中所有被
@Test
註解的方法 - Run All Tests with Coverage 檢查專案的測試覆蓋率
- 範例
@ExtendWith(MockitoExtension.class) public class UserServiceTest { @Mock private UserRepository userRepository; @InjectMocks private UserService userService = new UserService(); @Test public void test_getUserById_userExists() { //arrange Long userId = 1L; User user = new User(userId, "Tom"); when(userRepository.findById(userId)).thenReturn(Optional.of(user)); //act User result = userService.getUserById(userId); //assert assertEquals(user, result); } @Test public void test_getUserById_userNotFound() { //arrange Long userId = 2L; when(userRepository.findById(userId)).thenReturn(Optional.empty()); //act EntityNotFoundException exception = assertThrows(EntityNotFoundException.class, () -> { userService.getUserById(userId); }); //assert assertEquals("User not found with ID: 2", exception.getMessage()); } }