VieTopik
Tiếng HànTiếng AnhIT
  • Góc học tập
Tải app
  • Thư viện
  • Luyện thi
  • Cẩm nang
  • Góc học tập
Kiến trúc và chất lượng codeTest
Bài 5/17
5 phút

Parameterized test và nhiều trường hợp

Nội dung bài · 5 mục
  1. 1.Khái niệm
  2. 2.Ví dụ
  3. 3.Thử ngay
  4. 4.Lỗi hay gặp
  5. 5.Tóm tắt

Bài Viết test cho API của khoá Spring Boot đã có PriceCalculator và vài test @Test. Muốn kiểm tra thêm năm bộ giá và số lượng thì phải chép ra năm method gần giống hệt nhau. @ParameterizedTest cho một method test chạy với nhiều bộ dữ liệu.

Khái niệm

🧫 Parameterized test: method test nhận tham số, được đánh dấu @ParameterizedTest, chạy một lần cho mỗi bộ dữ liệu trong @CsvSource gắn kèm.

@Test là một test với dữ liệu cố định. Với @ParameterizedTest, mỗi dòng trong @CsvSource là một test riêng, xanh hay đỏ độc lập với các dòng khác.

Ví dụ

Dùng lại PriceCalculator của bài Viết test cho API: tổng từ 500.000 trở lên thì giảm 10%.

// PriceCalculator.java
package com.shop.api;

class PriceCalculator {
    public long total(long price, int quantity) {
        if (quantity <= 0) {
            throw new IllegalArgumentException(
                "Số lượng phải > 0");
        }

        long total = price * quantity;
        if (total >= 500000) {
            total = total * 90 / 100;
        }
        return total;
    }
}

Tạo file test mới trong src/test/java/com/shop/api/:

// TotalCasesTests.java
package com.shop.api;

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

import org.junit.jupiter.params.*;
import org.junit.jupiter.params.provider.*;

class TotalCasesTests {
    @ParameterizedTest
    @CsvSource({
        "100000, 2, 200000",
        "250000, 2, 450000",
        "300000, 2, 540000"
    })
    public void totalReturnsExpected(
            long price, int quantity, long expected) {
        var calculator = new PriceCalculator();

        long total = calculator.total(price, quantity);

        assertEquals(expected, total);
    }
}
  • Ba chuỗi trong @CsvSource là ba test. Mỗi chuỗi được tách theo dấu phẩy rồi truyền vào tham số theo đúng thứ tự: price, quantity, expected.
  • Giá trị viết dạng chuỗi, JUnit tự đổi "100000" sang long cho tham số price.
  • Dòng thứ hai rơi đúng mốc 500.000, chỗ dễ sai nhất như bài Viết test cho API đã chỉ ra.

Nên chọn dữ liệu theo nhóm: trường hợp bình thường, các mốc ranh giới, và dữ liệu không hợp lệ như số lượng 0.

Thử ngay

Thêm dòng "100000, 5, 500000" ngay dưới ba dòng trong @CsvSource của totalReturnsExpected (nhớ thêm dấu phẩy sau dòng thứ ba), rồi chạy ./mvnw test.

Đoán trước khi chạy: totalReturnsExpected giờ là mấy test, và dòng dữ liệu nào đỏ?

Xem kết quả
[ERROR] Tests run: 4, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.057 s <<< FAILURE! -- in com.shop.api.TotalCasesTests
[ERROR] com.shop.api.TotalCasesTests.totalReturnsExpected(long, int, long)[4] -- Time elapsed: 0.015 s <<< FAILURE!
...
[ERROR] Failures:
[ERROR]   TotalCasesTests.totalReturnsExpected:22 expected: <500000> but was: <450000>

Bốn dòng dữ liệu là bốn test: ba xanh, một đỏ. [4] cho biết bộ dữ liệu thứ tư hỏng. 100.000 × 5 đúng bằng 500.000 nên được giảm 10% còn 450.000, vậy kỳ vọng 500.000 là sai.

Dòng Tests run cuối cùng trên máy bạn còn cộng thêm các test cũ trong project.

Lỗi hay gặp

Viết số long có hậu tố L trong @CsvSource. Giá trị trong chuỗi không phải code Java, JUnit không đổi được "100000L" sang long. Test báo lỗi Failed to convert String "100000L" to type long.

// SAI — test lỗi khi chạy, không đổi được sang long
// DiscountTests.java
package com.shop.api;

import org.junit.jupiter.params.*;
import org.junit.jupiter.params.provider.*;

class DiscountTests {
    @ParameterizedTest
    @CsvSource("100000L, 2, 200000L")
    public void total(
            long price, int qty, long expected) {
    }
}
// ĐÚNG — viết số nguyên, JUnit tự đổi sang long
// DiscountTests.java
package com.shop.api;

import org.junit.jupiter.params.*;
import org.junit.jupiter.params.provider.*;

class DiscountTests {
    @ParameterizedTest
    @CsvSource("100000, 2, 200000")
    public void total(
            long price, int qty, long expected) {
    }
}

Tóm tắt

  • @ParameterizedTest kèm @CsvSource: một method, nhiều test.
  • Mỗi dòng dữ liệu xanh hay đỏ riêng, báo lỗi kèm số thứ tự bộ dữ liệu hỏng.
  • Chọn dữ liệu: trường hợp bình thường, mốc ranh giới, dữ liệu không hợp lệ.
  • Tiền trong @CsvSource viết số nguyên, không dùng hậu tố L.

Tự kiểm tra

0/3 câu
Câu 1

Một @ParameterizedTest có 5 dòng trong @CsvSource. ./mvnw test đếm bao nhiêu test?

Câu 2

Một @ParameterizedTest có 4 dòng dữ liệu, dòng thứ hai đỏ. Hai dòng sau nó có còn được chạy không, và kết quả của chúng tính thế nào?

Câu 3

@CsvSource("5000L, 1") làm test báo Failed to convert String "5000L" to type long. Sửa thế nào?

GitHub và pull requestFake thay phụ thuộc

Nội dung bài

  1. 1.Khái niệm
  2. 2.Ví dụ
  3. 3.Thử ngay
  4. 4.Lỗi hay gặp
  5. 5.Tóm tắt