JUnit เป็นเฟรมเวิร์กมาตรฐานสำหรับการทดสอบหน่วยในระบบนิเวศ Java และ Kotlin ซึ่งใช้ในการพัฒนา Android เพื่อตรวจสอบตรรกะทางธุรกิจในระดับของคอมโพเนนต์ที่แยกออกจากกัน เฟรมเวิร์กมีชุดของคำอธิบายประกอบ เมธอดการยืนยัน และ Test Runner สำหรับการค้นหาและดำเนินการทดสอบโดยอัตโนมัติ ตามข้อมูลจาก JUnit.org ไลบรารียังคงเป็นโซลูชันยอดนิยมที่สุดสำหรับการทดสอบหน่วยในระบบนิเวศ JVM: โปรเจกต์ Java กว่า 70% ใช้ JUnit ในเวอร์ชันใดเวอร์ชันหนึ่ง
ประเด็นสำคัญ
JUnit เป็นเฟรมเวิร์กโอเพนซอร์สสำหรับเขียนและเรียกใช้การทดสอบหน่วยที่ทำซ้ำได้ใน Java และ Kotlin เป็นส่วนหนึ่งของระบบนิเวศ xUnit ซึ่งเป็นตระกูลของเฟรมเวิร์กที่อิงตามสถาปัตยกรรมของ Kent Beck และ Erich Gamma และเป็นเครื่องมือทดสอบมาตรฐานใน Android Studio และ IntelliJ IDEA
งานหลักของ JUnit คือการแยกส่วนย่อยของโค้ด (เมธอด, คลาส) และตรวจสอบพฤติกรรมของมันภายใต้สภาวะที่ควบคุม การทดสอบถูกเขียนเป็นคลาส Java/Kotlin ปกติพร้อมคำอธิบายประกอบ และเฟรมเวิร์กจะจัดการการค้นหาการทดสอบ การจัดการวงจรชีวิต และการรวบรวมสถิติการดำเนินการ
JUnit เวอร์ชันแรกปรากฏในปี 1997 และเปลี่ยนแปลงแนวทางการพัฒนาอย่างสิ้นเชิงโดยทำให้แนวปฏิบัติ Test-Driven Development (TDD) เป็นที่นิยม ปัจจุบัน JUnit 5 (Jupiter) เป็นเวอร์ชันปัจจุบัน ซึ่งออกแบบใหม่ทั้งหมดด้วยสถาปัตยกรรมแบบโมดูลาร์ที่รองรับ Java 8+ และส่วนขยาย
กลไก การทำงานของ JUnit ขึ้นอยู่กับรูปแบบ Test Runner ซึ่งสแกน classpath ค้นหาเมธอดที่มีคำอธิบายประกอบ @Test สร้างอินสแตนซ์ของคลาสทดสอบ และเรียกใช้เมธอดในลำดับที่กำหนด Test Runner จัดการวงจรชีวิต: BeforeAll → BeforeEach → Test → AfterEach → AfterAll
JUnit ห่อแต่ละเมธอดทดสอบในอินสแตนซ์คลาสแยกต่างหาก ซึ่งรับประกัน การแยกส่วน ระหว่างการทดสอบ ซึ่งหมายความว่าฟิลด์ของคลาสจะไม่เก็บสถานะระหว่างเมธอด @Test ที่แตกต่างกัน — การทดสอบแต่ละครั้งเริ่มต้นด้วยวัตถุที่สะอาด
การทดสอบที่ง่ายที่สุดใน JUnit คือเมธอดที่มีคำอธิบายประกอบ @Test ซึ่งเรียกใช้โค้ดที่อยู่ภายใต้การทดสอบและตรวจสอบผลลัพธ์ผ่าน การยืนยัน หากการยืนยันล้มเหลว การทดสอบจะถือว่าล้มเหลวและ JUnit จะรายงานข้อผิดพลาด
@Test
void additionShouldReturnCorrectSum() {
var calculator = new Calculator();
var result = calculator.add(2, 3);
assertEquals(5, result);
}
Test Runner จะค้นหาเมธอดดังกล่าวโดยอัตโนมัติ เรียกใช้และรายงานผลลัพธ์ หากเมธอดไม่โยนข้อยกเว้น — การทดสอบผ่าน (green) หากการยืนยันล้มเหลว — การทดสอบล้มเหลว (red)
คำอธิบายประกอบ ใน JUnit กำหนดว่าเมื่อใดและอย่างไรที่โค้ดทดสอบควรดำเนินการ ใน JUnit 5 คำอธิบายประกอบอยู่ในแพ็คเกจ org.junit.jupiter.api และครอบคลุมทุกขั้นตอน: การเตรียมข้อมูล การดำเนินการทดสอบ การทำความสะอาดทรัพยากร
| คำอธิบายประกอบ | วัตถุประสงค์ | การดำเนินการ |
|---|---|---|
| @Test | ระบุเมธอดทดสอบ | หนึ่งครั้งต่อการเรียก |
| @BeforeEach | การตั้งค่าก่อนการทดสอบแต่ละครั้ง | ก่อนแต่ละ @Test |
| @BeforeAll | การเริ่มต้นคลาสครั้งเดียว | หนึ่งครั้งก่อนการทดสอบทั้งหมด |
| @AfterEach | การทำความสะอาดหลังการทดสอบแต่ละครั้ง | หลังแต่ละ @Test |
| @AfterAll | การสิ้นสุดคลาสครั้งเดียว | หนึ่งครั้งหลังการทดสอบทั้งหมด |
| @DisplayName | ชื่อการทดสอบที่มนุษย์อ่านได้ | การตกแต่ง |
พิจารณาคลาสทดสอบสมบูรณ์ที่มีวงจรชีวิตที่เหมาะสม เมธอด setUp สร้างอินสแตนซ์ Calculator ใหม่ก่อนการทดสอบแต่ละครั้ง และ tearDown ปลดปล่อยทรัพยากร — ตัวอย่างเช่น การปิดตัวบอกตำแหน่งไฟล์หรือการเชื่อมต่อฐานข้อมูล
class CalculatorTest {
private Calculator calculator;
@BeforeEach
void setUp() {
calculator = new Calculator();
}
@Test
void subtractionShouldReturnCorrectResult() {
int result = calculator.subtract(10, 4);
assertEquals(6, result);
}
@AfterEach
void tearDown() {
calculator.reset();
}
}
การยืนยัน เป็นเมธอดแบบสแตติกที่เปรียบเทียบผลลัพธ์จริงกับผลลัพธ์ที่คาดหวังและโยนข้อยกเว้นหากไม่ตรงกัน JUnit 5 มีคลาส org.junit.jupiter.api.Assertions พร้อมเมธอดมากกว่า 25 เมธอดสำหรับสถานการณ์การตรวจสอบที่หลากหลาย ตั้งแต่การเปรียบเทียบค่าง่ายไปจนถึงการตรวจสอบหมดเวลาและการยืนยันแบบกลุ่ม
เมธอด assertThrows สมควรได้รับความสนใจเป็นพิเศษ เพราะช่วยให้ตรวจสอบได้ว่าโค้ดจัดการกับสถานการณ์ข้อผิดพลาดอย่างถูกต้อง — การหารด้วยศูนย์ การส่ง null การเกินขีดจำกัด
@Test
void divisionByZeroShouldThrowException() {
Calculator calc = new Calculator();
ArithmeticException exception = assertThrows(
ArithmeticException.class,
() -> calc.divide(10, 0)
);
assertEquals("Cannot divide by zero", exception.getMessage());
}
การทดสอบแบบกำหนดพารามิเตอร์ อนุญาตให้เรียกใช้เมธอดทดสอบเดียวกันด้วยชุดอาร์กิวเมนต์ที่แตกต่างกัน ใน JUnit 5 ทำได้โดยใช้คำอธิบายประกอบ @ParameterizedTest ร่วมกับแหล่งข้อมูล — @ValueSource, @CsvSource, @MethodSource หรือ @EnumSource
วิธีการนี้ลดการทำซ้ำโค้ดอย่างสิ้นเชิง: แทนที่จะเขียนการทดสอบที่เหมือนกันสิบรายการสำหรับค่าที่แตกต่างกัน จะเขียนเมธอดแบบกำหนดพารามิเตอร์เพียงเมธอดเดียว ตาม Google Testing Blog การกำหนดพารามิเตอร์ช่วยลดปริมาณโค้ดทดสอบลง 40–60% โดยไม่สูญเสียความครอบคลุม
คำอธิบายประกอบ @CsvSource ส่งหลายแถวที่คั่นด้วยเครื่องหมายจุลภาคไปยังการทดสอบ แต่ละแถวสอดคล้องกับการเรียกใช้การทดสอบหนึ่งครั้ง JUnit แปลงค่าสตริงเป็นประเภทที่ต้องการโดยอัตโนมัติ: int, long, String และอื่นๆ
@ParameterizedTest
@CsvSource({
"1, 1, 2",
"2, 3, 5",
"10, 20, 30",
"-1, 1, 0"
})
void additionWithMultipleInputs(int a, int b, int expected) {
assertEquals(expected, a + b);
}
เมื่อข้อมูลป้อนเข้าซับซ้อนกว่าตัวเลขหรือสตริงธรรมดา จะใช้ @MethodSource ซึ่งอ้างอิงถึงเมธอดแบบสแตติกที่ส่งคืน Stream ของอาร์กิวเมนต์ — ตัวอย่างเช่น Stream ของ Arguments หรือ Stream ของวัตถุ User สำหรับการทดสอบชั้น DAO
ในการพัฒนา Android JUnit ถูกใช้ร่วมกับ AndroidX Test ซึ่งมีส่วนขยายสำหรับการทดสอบ Activity, Content Provider และคอมโพเนนต์ Android อื่นๆ JUnit จัดการการทดสอบหน่วยที่ทำงานบน JVM โดยไม่ต้องใช้โปรแกรมจำลอง ในขณะที่ AndroidX Test จัดการการทดสอบที่ใช้เครื่องมือบนอุปกรณ์
เพื่อเพิ่ม JUnit 5 ในโปรเจกต์ Android เพียงเพิ่มการพึ่งพา org.junit.jupiter:junit-jupiter ใน build.gradle ระดับโมดูล ปลั๊กอิน AGP Gradle รองรับการเรียกใช้การทดสอบ JUnit 5 บน JVM ผ่าน Test Runner มาตรฐาน
// build.gradle.kts
android {
testOptions {
unitTests.isIncludeAndroidResources = true
}
}
dependencies {
testImplementation("org.junit.jupiter:junit-jupiter:5.11.0")
testImplementation("androidx.test:core-ktx:1.6.1")
}
ในทางปฏิบัติ JUnit มักใช้สำหรับการทดสอบ ViewModel และพื้นที่เก็บข้อมูล — ชั้นที่ไม่ต้องการบริบท Android หรือโปรแกรมจำลอง การทดสอบดังกล่าวทำงานในหน่วยมิลลิวินาทีและสามารถดำเนินการได้หลายร้อยครั้งโดยไม่เสียเวลา
JUnit 5 (Jupiter) ไม่ใช่แค่เวอร์ชันใหม่ แต่เป็นแพลตฟอร์มที่ออกแบบใหม่ทั้งหมดแบ่งออกเป็นสามโมดูล: JUnit Platform (การดำเนินการทดสอบบน JVM), JUnit Jupiter (API สำหรับเขียนการทดสอบ) และ JUnit Vintage (ความเข้ากันได้ย้อนหลังกับ JUnit 4) ความเป็นโมดูลาร์นี้ช่วยให้สามารถเชื่อมต่อ Test Engine ที่แตกต่างกัน — ตัวอย่างเช่น Spek สำหรับ Kotlin หรือ TestNG
| คุณลักษณะ | JUnit 4 | JUnit 5 |
|---|---|---|
| แพ็คเกจ | org.junit | org.junit.jupiter |
| คำอธิบายประกอบพื้นฐาน | @Test (จาก junit.framework) | @Test (จาก org.junit.jupiter.api) |
| Before/After | @Before, @After, @BeforeClass | @BeforeEach, @AfterEach, @BeforeAll |
| กำหนดพารามิเตอร์ | @RunWith(Parameterized.class) | @ParameterizedTest + @ValueSource |
| ส่วนขยาย | @Rule, @ClassRule | @ExtendWith, API ที่ยืดหยุ่นกว่า |
| Java ขั้นต่ำ | Java 5 | Java 8+ |
การย้ายจาก JUnit 4 ไป JUnit 5 ไม่จำเป็นต้องเขียนการทดสอบทั้งหมดใหม่ — เพียงเพิ่ม JUnit Vintage Engine และการทดสอบเก่าจะยังคงทำงานได้ การทดสอบใหม่แนะนำให้เขียนด้วย JUnit 5 เพื่อใช้ประโยชน์จากส่วนขยาย การยืนยันแบบแลมบ์ดา และการสนับสนุน การกำหนดพารามิเตอร์ ในตัว
คำถามที่พบบ่อย
JUnit เป็นเฟรมเวิร์กสำหรับเขียนและเรียกใช้การทดสอบ ในขณะที่ Mockito เป็นไลบรารีสำหรับสร้างวัตถุจำลอง พวกมันถูกใช้ร่วมกัน: JUnit จัดการการดำเนินการทดสอบ และ Mockito แทนที่การพึ่งพาของคลาสที่อยู่ภายใต้การทดสอบ
ได้ JUnit 5 เข้ากันได้อย่างสมบูรณ์กับโปรเจกต์ Android สำหรับการทดสอบหน่วย เพียงเพิ่มการพึ่งพา junit-jupiter ใน build.gradle การทดสอบที่ใช้เครื่องมือยังคงทำงานผ่าน AndroidX Test Runner
อย่างน้อยที่สุด คำอธิบายประกอบ @Test เพียงตัวเดียวก่อนเมธอดก็เพียงพอแล้ว @BeforeEach และ @AfterEach แนะนำสำหรับการเริ่มต้นและการทำความสะอาด แต่ไม่จำเป็น
Test Runner เป็นคอมโพเนนต์ของ JUnit ที่สแกน classpath ค้นหาเมธอดที่มีคำอธิบายประกอบ @Test สร้างอินสแตนซ์ของคลาสทดสอบและเรียกใช้การทดสอบ ใน JUnit 5 บทบาทนี้ดำเนินการโดย JUnit Platform พร้อมกับ Test Engine ที่เชื่อมต่อ
ใช้ assertThrows(Class, Executable) — มันรับประเภทข้อยกเว้นที่คาดหวังและแลมบ์ดาพร้อมการเรียกเมธอด JUnit ตรวจสอบว่าข้อยกเว้นถูกโยนจริงและส่งคืนเพื่อการตรวจสอบเพิ่มเติม
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม