Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Java

JUnit 5 Annotations: คู่มือครบวงจร พร้อมตัวอย่างและ Setup Maven/Gradle

JUnit 5 เป็นเวอร์ชันล่าสุดของ Testing Framework ยอดนิยมสำหรับ JVM รองรับ Java 8+ และมี Annotations ใหม่หลายตัว บทความนี้ครอบคลุมทุก Annotations หลักพร้อมโค้ดตัวอย่าง

Setup: Maven Dependency

<dependencies>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <version>5.10.2</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-params</artifactId>
        <version>5.10.2</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-engine</artifactId>
        <version>5.10.2</version>
        <scope>test</scope>
    </dependency>
</dependencies>

Annotations หลัก

@Test - เมธอดทดสอบพื้นฐาน

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

class JUnit5Test {
    @Test
    void helloJUnit5() {
        assertEquals(10, 5 + 5);
    }
}

✅ การเปลี่ยนแปลงจาก JUnit 4: Class และ Method ไม่ต้องเป็น public แล้ว

@ParameterizedTest - ทดสอบหลายค่า

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import static org.junit.jupiter.api.Assertions.*;

class JUnit5Test {
    @ParameterizedTest
    @ValueSource(strings = {"cali", "bali", "dani"})
    void endsWithI(String str) {
        assertTrue(str.endsWith("i"));
    }
}

Argument Sources อื่นๆ: @EnumSource, @MethodSource, @CsvSource, @CsvFileSource

@RepeatedTest - ทดสอบซ้ำหลายครั้ง

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.RepetitionInfo;
import org.junit.jupiter.api.TestInfo;
import static org.junit.jupiter.api.Assertions.*;

class JUnit5Test {
    @RepeatedTest(value = 5, name = "{displayName} {currentRepetition}/{totalRepetitions}")
    @DisplayName("Repeating Test")
    void customDisplayName(RepetitionInfo repInfo, TestInfo testInfo) {
        System.out.println(testInfo.getDisplayName() + " -> " + repInfo.getCurrentRepetition());
        // Test logic here
    }
}

✅ เหมาะสำหรับ: Flaky tests, UI testing (Selenium), Load testing

@DisplayName - ชื่อทดสอบที่อ่านง่าย

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;

@DisplayName("User Service Tests")
class UserServiceTest {
    @Test
    @DisplayName("Should return user when valid ID provided")
    void testFindById() { }
    
    @Test
    @DisplayName("Should throw exception when user not found")
    void testNotFound(TestInfo testInfo) {
        System.out.println(testInfo.getDisplayName());
    }
}

@BeforeEach / @AfterEach - Setup/Teardown ต่อ Test

import org.junit.jupiter.api.*;

class LifecycleTest {
    @BeforeEach
    void setUp(TestInfo testInfo) {
        System.out.println("Before: " + testInfo.getTestMethod().get().getName());
    }
    
    @Test void firstTest() { System.out.println("Test 1"); }
    @Test void secondTest() { System.out.println("Test 2"); }
    
    @AfterEach
    void tearDown(TestInfo testInfo) {
        System.out.println("After: " + testInfo.getTestMethod().get().getName());
    }
}
// Output:
// Before: firstTest
// Test 1
// After: firstTest
// Before: secondTest
// Test 2
// After: secondTest

@BeforeAll / @AfterAll - Setup/Teardown ครั้งเดียวสำหรับ Class

import org.junit.jupiter.api.*;

class LifecycleTest {
    @BeforeAll
    static void initAll() {
        System.out.println("Run once before all tests");
    }
    
    @AfterAll
    static void tearDownAll() {
        System.out.println("Run once after all tests");
    }
    
    @Test void test1() { System.out.println("Test 1"); }
    @Test void test2() { System.out.println("Test 2"); }
}
// Output:
// Run once before all tests
// Test 1
// Test 2
// Run once after all tests

⚠️ สำคัญ: @BeforeAll และ @AfterAll ต้องเป็น static method

@Tag - กรอง Test (Filtering)

import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;

@Tag("smoke")
class JUnit5Test {
    @Test @Tag("login") void validLoginTest() { }
    @Test @Tag("search") void searchTest() { }
}

รันเฉพาะ smoke test: mvn test -Dgroups=smoke

@Disabled - ปิดการทดสอบ

import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;

@Disabled // ปิดทั้ง Class
class DisabledClassDemo {
    @Test void testWillBeSkipped() { }
}

class DisabledTestsDemo {
    @Disabled @Test void testWillBeSkipped() { } // ปิดแค่ Method
    @Test void testWillBeExecuted() { }
}

Annotations เพิ่มเติมที่น่าสนใจ

Annotationคำอธิบาย
@NestedNested test classes (Inner class)
@TestFactoryDynamic Tests (สร้าง Test Runtime)
@TestTemplateTemplate for test cases
@ExtendWithRegister Extensions (Mockito, Spring, etc.)
@TimeoutSet timeout for test
@Orderระบุลำดับการรัน Test (กับ @TestMethodOrder)

Assertions ที่ใช้บ่อย

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

assertEquals(expected, actual);
assertNotEquals(unexpected, actual);
assertTrue(condition);
assertFalse(condition);
assertNull(object);
assertNotNull(object);
assertSame(expected, actual); // same reference
assertThrows(Exception.class, () -> { ... });
assertAll("group", () -> assertTrue(...), () -> assertEquals(...)); // Grouped assertions

บทความเกี่ยวข้อง