JUnit: nó là gì, các khái niệm chính và cách hoạt động

Tác giả: IT Sectr Đã đăng: 2026-04-08 Thời gian đọc: 8 phút

JUnit là một framework tiêu chuẩn cho kiểm thử đơn vị trong hệ sinh thái Java và Kotlin, được sử dụng trong phát triển Android để xác minh logic kinh doanh ở cấp độ các thành phần độc lập. Framework cung cấp một tập hợp các chú thích, phương thức khẳng định và Test Runner để tự động phát hiện và thực thi các bài kiểm thử. Theo JUnit.org, thư viện này vẫn là giải pháp phổ biến nhất cho kiểm thử đơn vị trong hệ sinh thái JVM: hơn 70% các dự án Java sử dụng JUnit ở bất kỳ phiên bản nào.

Những điểm chính

  • JUnit là một framework mã nguồn mở cho kiểm thử đơn vị mã Java và Kotlin.
  • Chú thích — @Test, @BeforeEach, @BeforeAll quản lý vòng đời của lớp kiểm thử.
  • Khẳng định — assertEquals, assertTrue, assertThrows xác minh kết quả thực thi mong đợi.
  • Kiểm thử tham số hóa — cho phép chạy một kiểm thử với các bộ dữ liệu đầu vào khác nhau.
  • Test Runner — cơ sở hạ tầng JUnit tự động tìm và chạy tất cả các kiểm thử trong dự án.

JUnit là gì?

JUnit là một framework mã nguồn mở để viết và chạy các kiểm thử đơn vị có thể lặp lại trong Java và Kotlin. Nó là một phần của hệ sinh thái xUnit, một họ các framework dựa trên kiến trúc của Kent Beck và Erich Gamma, và là công cụ kiểm thử tiêu chuẩn trong Android Studio và IntelliJ IDEA.

Nhiệm vụ chính của JUnit là cô lập một đoạn mã nhỏ (phương thức, lớp) và xác minh hành vi của nó trong các điều kiện được kiểm soát. Các kiểm thử được viết dưới dạng các lớp Java/Kotlin thông thường với các chú thích, và framework đảm nhận việc phát hiện kiểm thử, quản lý vòng đời và thu thập thống kê thực thi.

Phiên bản đầu tiên của JUnit xuất hiện vào năm 1997 và đã thay đổi triệt để cách tiếp cận phát triển bằng cách phổ biến các thực hành Phát triển hướng kiểm thử (TDD). Ngày nay, JUnit 5 (Jupiter) là phiên bản hiện tại, được thiết kế lại hoàn toàn với kiến trúc mô-đun hỗ trợ Java 8+ và các tiện ích mở rộng.

Cách JUnit hoạt động

Cơ chế thực thi của JUnit dựa trên mẫu Test Runner, quét classpath, tìm các phương thức có chú thích @Test, tạo một thể hiện của lớp kiểm thử và chạy các phương thức theo một thứ tự cụ thể. Test Runner quản lý vòng đời: BeforeAll → BeforeEach → Test → AfterEach → AfterAll.

Vòng đời của lớp kiểm thử

JUnit bao bọc mỗi phương thức kiểm thử trong một thể hiện lớp riêng biệt, đảm bảo sự cô lập giữa các kiểm thử. Điều này có nghĩa là các trường của lớp không giữ trạng thái giữa các phương thức @Test khác nhau — mỗi kiểm thử bắt đầu với một đối tượng sạch.

Cấu trúc kiểm thử cơ bản

Kiểm thử đơn giản nhất trong JUnit là một phương thức có chú thích @Test gọi mã đang được kiểm thử và xác minh kết quả thông qua một khẳng định. Nếu khẳng định thất bại, kiểm thử được coi là thất bại và JUnit báo cáo lỗi.

java
@Test
void additionShouldReturnCorrectSum() {
    var calculator = new Calculator();
    var result = calculator.add(2, 3);
    assertEquals(5, result);
}

Test Runner tự động tìm phương thức như vậy, chạy nó và báo cáo kết quả. Nếu phương thức không ném ngoại lệ — kiểm thử thành công (green). Nếu một khẳng định thất bại — kiểm thử thất bại (red).

Chú thích JUnit: vòng đời kiểm thử

Các chú thích trong JUnit xác định thời điểm và cách thức mã kiểm thử nên thực thi. Trong JUnit 5, các chú thích nằm trong gói org.junit.jupiter.api và bao gồm tất cả các giai đoạn: chuẩn bị dữ liệu, thực thi kiểm thử, dọn dẹp tài nguyên.

Chú thíchMục đíchThực thi
@TestĐánh dấu phương thức kiểm thửMột lần mỗi lần gọi
@BeforeEachThiết lập trước mỗi kiểm thửTrước mỗi @Test
@BeforeAllKhởi tạo lớp một lầnMột lần trước tất cả kiểm thử
@AfterEachDọn dẹp sau mỗi kiểm thửSau mỗi @Test
@AfterAllKết thúc lớp một lầnMột lần sau tất cả kiểm thử
@DisplayNameTên kiểm thử dễ đọcTrang trí

Ví dụ sử dụng chú thích

Hãy xem xét một lớp kiểm thử hoàn chỉnh với vòng đời phù hợp. Phương thức setUp tạo một thể hiện Calculator mới trước mỗi kiểm thử, và tearDown giải phóng tài nguyên — ví dụ, đóng các bộ mô tả tệp hoặc kết nối cơ sở dữ liệu.

java
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();
    }
}

Khẳng định: xác minh kết quả trong JUnit

Các khẳng định là các phương thức tĩnh so sánh kết quả thực tế với kết quả mong đợi và ném ngoại lệ nếu không khớp. JUnit 5 cung cấp lớp org.junit.jupiter.api.Assertions với hơn 25 phương thức cho các kịch bản xác minh khác nhau — từ so sánh giá trị đơn giản đến kiểm tra thời gian chờ và các khẳng định nhóm.

  • assertEquals(expected, actual) — kiểm tra sự bằng nhau qua equals().
  • assertTrue(condition) — kiểm tra rằng điều kiện là đúng.
  • assertFalse(condition) — kiểm tra rằng điều kiện là sai.
  • assertNotNull(object) — kiểm tra rằng đối tượng không phải null.
  • assertNull(object) — kiểm tra rằng đối tượng là null.
  • assertThrows(exception, executable) — kiểm tra rằng mã ném một ngoại lệ cụ thể.
  • assertAll(executables) — nhóm nhiều khẳng định và thực thi tất cả mà không dừng lại ở lỗi đầu tiên.

assertThrows để kiểm tra ngoại lệ

Phương thức assertThrows đáng được chú ý đặc biệt, vì nó cho phép xác minh rằng mã xử lý chính xác các tình huống lỗi — chia cho không, truyền null, vượt quá giới hạn.

java
@Test
void divisionByZeroShouldThrowException() {
    Calculator calc = new Calculator();

    ArithmeticException exception = assertThrows(
        ArithmeticException.class,
        () -> calc.divide(10, 0)
    );

    assertEquals("Cannot divide by zero", exception.getMessage());
}

Kiểm thử tham số hóa trong JUnit

Kiểm thử tham số hóa cho phép chạy cùng một phương thức kiểm thử với các bộ đối số khác nhau. Trong JUnit 5, điều này được thực hiện bằng cách sử dụng chú thích @ParameterizedTest kết hợp với một nguồn dữ liệu — @ValueSource, @CsvSource, @MethodSource hoặc @EnumSource.

Cách tiếp cận này giảm triệt để sự trùng lặp mã: thay vì mười kiểm thử giống hệt nhau cho các giá trị khác nhau, bạn viết một phương thức tham số hóa duy nhất. Theo Google Testing Blog, tham số hóa giảm khối lượng mã kiểm thử từ 40–60% mà không mất đi độ phủ.

Ví dụ với CsvSource

Chú thích @CsvSource truyền nhiều dòng được phân tách bằng dấu phẩy vào kiểm thử. Mỗi dòng tương ứng với một lần chạy kiểm thử. JUnit tự động chuyển đổi các giá trị chuỗi thành các kiểu cần thiết: int, long, String và các kiểu khác.

java
@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 cho các đối tượng phức tạp

Khi dữ liệu đầu vào phức tạp hơn các số hoặc chuỗi đơn giản, @MethodSource được sử dụng. Nó tham chiếu đến một phương thức tĩnh trả về một Stream các đối số — ví dụ: một Stream các Arguments hoặc một Stream các đối tượng User để kiểm thử lớp DAO.

Tích hợp JUnit với các dự án Android

Trong phát triển Android, JUnit được sử dụng cùng với AndroidX Test, cung cấp các tiện ích mở rộng để kiểm thử Activity, Content Provider và các thành phần Android khác. JUnit đảm nhận các kiểm thử đơn vị được thực thi trên JVM mà không cần trình giả lập, trong khi AndroidX Test đảm nhận các kiểm thử công cụ trên thiết bị.

Thiết lập Gradle

Để thêm JUnit 5 vào một dự án Android, chỉ cần bao gồm phụ thuộc org.junit.jupiter:junit-jupiter trong build.gradle cấp mô-đun. Plugin AGP Gradle hỗ trợ chạy các kiểm thử JUnit 5 trên JVM thông qua Test Runner tiêu chuẩn.

kotlin
// 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")
}

Kiểm thử ViewModel với JUnit

Trong thực tế, JUnit thường được sử dụng nhất để kiểm thử ViewModel và các kho lưu trữ — các lớp không yêu cầu ngữ cảnh Android hoặc trình giả lập. Một kiểm thử như vậy chạy trong mili giây và có thể được thực thi hàng trăm lần mà không mất thời gian.

  • ViewModel — xác minh trạng thái: loading, success, error.
  • Repository — xác minh ánh xạ dữ liệu và xử lý lỗi.
  • UseCase — xác minh logic kinh doanh với các mock phụ thuộc.

JUnit 4 vs JUnit 5: khác biệt chính

JUnit 5 (Jupiter) không chỉ là một phiên bản mới, mà là một nền tảng được thiết kế lại hoàn toàn chia thành ba mô-đun: JUnit Platform (thực thi kiểm thử trên JVM), JUnit Jupiter (API để viết kiểm thử) và JUnit Vintage (tương thích ngược với JUnit 4). Tính mô-đun này cho phép kết nối các Test Engine khác nhau — ví dụ: Spek cho Kotlin hoặc TestNG.

Đặc điểmJUnit 4JUnit 5
Góiorg.junitorg.junit.jupiter
Chú thích cơ bản@Test (từ junit.framework)@Test (từ org.junit.jupiter.api)
Before/After@Before, @After, @BeforeClass@BeforeEach, @AfterEach, @BeforeAll
Tham số hóa@RunWith(Parameterized.class)@ParameterizedTest + @ValueSource
Tiện ích mở rộng@Rule, @ClassRule@ExtendWith, API linh hoạt hơn
Java tối thiểuJava 5Java 8+

Di chuyển từ JUnit 4 sang JUnit 5 không yêu cầu viết lại tất cả các kiểm thử — chỉ cần thêm JUnit Vintage Engine và các kiểm thử cũ sẽ tiếp tục hoạt động. Các kiểm thử mới được khuyến nghị viết bằng JUnit 5 để tận dụng các tiện ích mở rộng, khẳng định lambda và hỗ trợ tham số hóa tích hợp sẵn.

Câu hỏi thường gặp

JUnit khác Mockito như thế nào?

JUnit là một framework để viết và chạy các kiểm thử, trong khi Mockito là một thư viện để tạo các đối tượng mock. Chúng được sử dụng cùng nhau: JUnit quản lý việc thực thi kiểm thử và Mockito thay thế các phụ thuộc của lớp được kiểm thử.

Có thể sử dụng JUnit 5 trong các dự án Android không?

Có, JUnit 5 hoàn toàn tương thích với các dự án Android. Đối với kiểm thử đơn vị, chỉ cần thêm phụ thuộc junit-jupiter trong build.gradle. Các kiểm thử công cụ vẫn hoạt động thông qua AndroidX Test Runner.

Bộ chú thích tối thiểu cần cho một kiểm thử là gì?

Tối thiểu, một chú thích @Test duy nhất trước phương thức là đủ. @BeforeEach và @AfterEach được khuyến nghị để khởi tạo và dọn dẹp, nhưng không bắt buộc.

Test Runner trong JUnit là gì?

Test Runner là một thành phần của JUnit quét classpath, tìm các phương thức có chú thích @Test, tạo các thể hiện của lớp kiểm thử và chạy các kiểm thử. Trong JUnit 5, vai trò này được thực hiện bởi JUnit Platform với các Test Engine được kết nối.

Làm thế nào để xác minh rằng một phương thức ném ngoại lệ?

Sử dụng assertThrows(Class, Executable) — nó nhận loại ngoại lệ mong đợi và một lambda với lời gọi phương thức. JUnit xác minh rằng ngoại lệ thực sự đã được ném và trả về nó để kiểm tra thêm.

Tổng kết

  • JUnit là framework kiểm thử đơn vị tiêu chuẩn cho Java và Kotlin, nền tảng của hệ sinh thái xUnit.
  • Chú thích @Test, @BeforeEach, @AfterEach quản lý vòng đời của lớp kiểm thử.
  • Khẳng định — assertEquals, assertTrue, assertThrows xác minh tính chính xác của kết quả.
  • Kiểm thử tham số hóa với @CsvSource và @MethodSource giảm trùng lặp mã.
  • JUnit 5 — kiến trúc mô-đun với nền tảng, API Jupiter và hỗ trợ tiện ích mở rộng.
  • Tích hợp Android — JUnit chạy trên JVM thông qua Test Runner tiêu chuẩn không cần trình giả lập.
  • Test Runner tự động phát hiện và chạy các phương thức @Test, báo cáo kết quả.

Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay

IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.

Thảo luận dự án

Đọc thêm