Parameterized test và nhiều trường hợp
Nội dung bài · 5 mục
- 1.Khái niệm
- 2.Ví dụ
- 3.Thử ngay
- 4.Lỗi hay gặp
- 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
@CsvSourcelà 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"sanglongcho 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
@ParameterizedTestkè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
@CsvSourceviết số nguyên, không dùng hậu tốL.
Tự kiểm tra
0/3 câuMột @ParameterizedTest có 5 dòng trong @CsvSource. ./mvnw test đếm bao nhiêu test?
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?
@CsvSource("5000L, 1") làm test báo Failed to convert String "5000L" to type long. Sửa thế nào?