首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

JUnit 5 單元測試實戰:從入門到規範的完整指南

     編輯:Java 相關知識

為什麼需要單元測試框架?

傳統 main 方法測試痛點:需手動調用、人工比對結果、無法批量執行、無報告統計。JUnit 解決了自動化執行、斷言驗證、生命周期管理、測試報告生成等核心需求。

一、JUnit 5 核心註解速查

註解執行時機用途限制
@Test每個測試方法標識測試入口非 static、無參、void 返回
@BeforeEach每個 @Test 前準備測試數據/環境
@AfterEach每個 @Test 後清理資源/重置狀態
@BeforeAll所有測試前一次昂貴資源初始化(如數據庫連接)必須 static
@AfterAll所有測試後一次釋放共享資源必須 static
@Disabled-暫時禁用測試可加原因說明

二、斷言 API 核心用法

import static org.junit.jupiter.api.Assertions.*;

@Test
void assertionDemo() {
    // 相等性斷言
    assertEquals(4, 2 + 2, "基本加法驗證");
    assertEquals("hello", "HELLO".toLowerCase());
    
    // 精度比較(浮點數)
    assertEquals(3.14159, Math.PI, 0.00001);
    
    // 引用同一性
    String s1 = "test";
    String s2 = s1;
    assertSame(s1, s2);
    
    // 條件斷言
    assertTrue(List.of(1,2,3).contains(2));
    assertFalse("".isEmpty());
    
    // 空值檢查
    assertNull(null);
    assertNotNull(new Object());
    
    // 異常斷言(JUnit 5 新特性)
    assertThrows(IllegalArgumentException.class, () -> {
        throw new IllegalArgumentException("參數非法");
    });
    
    // 多條斷言組合(全部執行、匯總報錯)
    assertAll("用戶對象驗證",
        () -> assertEquals("張三", user.getName()),
        () -> assertTrue(user.getAge() > 18)
    );
}

三、測試命名與組織規範

  1. 類命名:被測類名 + Test(如 UserServiceTest)
  2. 方法命名:test + 被測方法名 + _場景_預期結果(如 testLogin_success_whenCredentialsValid)
  3. 包結構:鏡像主代碼包結構,放在 src/test/java

四、完整實戰案例:文件讀取與排序服務測試

@DisplayName("文件處理服務測試")
class FileProcessorTest {

    private static final Path TEST_FILE = Path.of("target/test-data/input.txt");
    private FileProcessor processor;

    @BeforeAll
    static void setupClass() throws IOException {
        // 創建測試文件
        Files.createDirectories(TEST_FILE.getParent());
        Files.writeString(TEST_FILE, "3\n1\n2\n");
    }

    @AfterAll
    static void tearDownClass() throws IOException {
        Files.deleteIfExists(TEST_FILE);
    }

    @BeforeEach
    void setUp() {
        processor = new FileProcessor();
    }

    @Test
    @DisplayName("正確讀取文件並按升序排序")
    void readAndSort_validFile_returnsSortedList() throws IOException {
        List<Integer> result = processor.readAndSort(TEST_FILE);
        assertEquals(List.of(1, 2, 3), result);
    }

    @Test
    @DisplayName("文件不存在時拋出異常")
    void readAndSort_fileNotFound_throwsException() {
        Path notExist = Path.of("not-exist.txt");
        assertThrows(IOException.class, () -> processor.readAndSort(notExist));
    }

    @ParameterizedTest  // 參數化測試 JUnit 5 新特性
    @ValueSource(strings = {"", "   ", "\n\t"})
    @DisplayName("空白文件返回空列表")
    void readAndSort_blankFile_returnsEmptyList(String content) throws IOException {
        Path temp = Files.createTempFile("blank-", ".txt");
        Files.writeString(temp, content);
        assertTrue(processor.readAndSort(temp).isEmpty());
        Files.deleteIfExists(temp);
    }
}

五、進階技巧

  • 參數化測試:@ParameterizedTest + @ValueSource/@CsvSource/@MethodSource 減少重複代碼。
  • 嵌套測試:@Nested 內部類組織相關測試場景。
  • 標籤過濾:@Tag("slow") 標記慢測試,CI 階段排除。
  • 測試模板:@TestTemplate 定義可擴展測試模板。

六、最佳實踐總結

  1. F.I.R.S.T 原則:Fast(快)、Independent(獨立)、Repeatable(可重複)、Self-validating(自驗證)、Timely(及時)。
  2. 測試代碼質量同等重要:消除重複、清晰表達意圖、避免邏輯過度複雜。
  3. 邊界條件、異常路徑、業務核心路徑全覆蓋。
  4. 集成測試與單元測試分離(不同 Profile/模塊)。
  5. 斷言信息要有業務語義,失敗時可直接定位問題。

掌握 JUnit 5 的現代特性與規範實踐,能構建高可維護性的測試套件,為重構與持續交付提供安全網。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved