JUnit Kiểm tra tham số hóa với ví dụ sử dụng @Parameters

⚡ Tóm tắt thông minh

Các bài kiểm tra tham số trong JUnit Chạy phương pháp kiểm thử tương tự nhiều lần với các giá trị đầu vào khác nhau, sao cho một phương pháp có thể bao quát nhiều trường hợp. Các chú thích @RunWith và @Parameters cung cấp tập dữ liệu cho mỗi lần lặp.

  • 🔘 Nguồn dữ liệu: Một phương thức tĩnh `@Parameters` trả về một tập hợp các mảng, và mỗi mảng trở thành một lần lặp kiểm thử.
  • ☑️ Runner: @RunWith(Parameterized.class) thay thế Block mặc địnhJUnit4ClassRunner sẽ xây dựng lại lớp một lần cho mỗi hàng dữ liệu.
  • Người xây dựng: Một hàm tạo công khai lưu trữ một hàng dữ liệu duy nhất trong các trường của đối tượng mà phương thức kiểm thử sử dụng để khẳng định.
  • 🧪 Ví dụ thực tế: Năm hàng dữ liệu đầu vào điều khiển phép kiểm tra sum(), và JUnit Xem báo cáo. Chạy 5/5 lần không có lỗi nào.
  • 🛠️ JUnit 5: Việc sử dụng @ParameterizedTest với @ValueSource, @CsvSource hoặc @MethodSource sẽ loại bỏ cả trình chạy và hàm tạo.
  • 📌 Cạm bẫy: Một phương thức @Parameters không tĩnh, hai hàm tạo công khai hoặc thiếu phụ thuộc junit-jupiter-params sẽ khiến quá trình chạy dừng lại.

JUnit Kiểm thử tham số hóa sử dụng chú thích @RunWith và @Parameters

Kiểm thử tham số hóa là gì? JUnit?

A kiểm tra tham số Đây là một bài kiểm tra thực thi cùng một phương thức kiểm thử nhiều lần với các giá trị khác nhau. Nó giúp các nhà phát triển tiết kiệm thời gian khi viết các bài kiểm thử chỉ khác nhau ở đầu vào và kết quả mong đợi.

Sử dụng kiểm thử tham số hóa, người ta có thể thiết lập một phương thức kiểm thử để lấy dữ liệu từ một nguồn dữ liệu nào đó. Điều này làm cho nó trở thành hình thức đơn giản nhất của... thử nghiệm dựa trên dữ liệu có sẵn bên trong JUnit Nó hoạt động độc lập, không cần thư viện bên ngoài.

Hãy xem xét một bài kiểm tra đơn giản cộng các số khác nhau. Đoạn mã có thể trông như thế này:

JUnit Phương thức kiểm thử lặp lại ba lần lệnh assertEquals cho phương thức sum.

Cách tiếp cận trên dẫn đến rất nhiều sự dư thừa. Mỗi cặp số mới cần một câu lệnh assert khác bên trong cùng một phương thức, và lỗi ở câu lệnh assert đầu tiên sẽ che khuất mọi câu lệnh assert tiếp theo.

Cần một cách tiếp cận đơn giản hơn. Sử dụng kiểm thử tham số hóa, bạn có thể thêm một phương thức duy nhất cung cấp mười dữ liệu đầu vào, và bài kiểm thử của bạn sẽ tự động chạy mười lần.

Các bước để tạo một tham số JUnit Thử nghiệm

Đoạn mã sau đây minh họa một ví dụ về kiểm thử tham số. Nó kiểm thử phương thức sum() của lớp Airthematic, đây là cách viết được sử dụng xuyên suốt dự án mẫu.

Bước 1) Tạo một lớp. Trong ví dụ này, chúng ta sẽ nhập hai số bằng cách sử dụng phương thức sum(int, int), phương thức này sẽ trả về tổng của hai số đã cho.

Lớp Airthematic khai báo một phương thức sum công khai cộng hai đối số kiểu int.

Bước 2) Tạo một lớp kiểm thử có tham số.

Tệp tiêu đề lớp kiểm thử được chú thích bằng @RunWith(Parameterized.class) và bốn trường riêng tư.

Code Giải thích

  • Code Dòng 11: Hãy chú thích lớp kiểm thử của bạn bằng cách sử dụng @RunWith(Parameterized.class).
  • Code Dòng 13: Khai báo biến 'firstNumber' là riêng tư và gõ là int.
  • Code Dòng 14: Khai báo biến 'secondNumber' là private và kiểu dữ liệu là int.
  • Code Dòng 15: Khai báo biến 'expectedResult' là private và kiểu dữ liệu là int.
  • Code Dòng 16: Khai báo biến 'airthematic' là private và kiểu dữ liệu là Airthematic.

@RunWith(class_name.class): the @RunWith Chú thích được sử dụng để chỉ định tên lớp chạy của nó. Nếu chúng ta không chỉ định bất kỳ kiểu nào làm tham số, thời gian chạy sẽ tự chọn. ChặnJUnit4LớpÁ hậu theo mặc định.

Lớp này chịu trách nhiệm chạy các bài kiểm tra với một thể hiện kiểm thử mới. Nó chịu trách nhiệm gọi... JUnit Các phương pháp vòng đời như thiết lập (liên kết tài nguyên) và gỡ bỏ (giải phóng tài nguyên), được mô tả trong phần sau: JUnit lịch thi đấu hướng dẫn.

Để tham số hóa, bạn cần chú thích lớp bằng @RunWith và truyền vào đối tượng .class cần kiểm thử.

Bước 3) Hãy tạo một hàm tạo để lưu trữ dữ liệu kiểm thử. Hàm tạo này sẽ lưu trữ 3 biến.

Hàm tạo kiểm thử có tham số gán ba đối số kiểu int cho các trường của đối tượng.

Bước 4) Tạo một phương thức tĩnh tạo và trả về dữ liệu thử nghiệm.

Phương thức nhập tĩnh được chú thích bằng @Parameterized.Parameters trả về một mảng Object hai chiều.

Code Dòng 32,33: Tạo một mảng hai chiều (cung cấp các tham số đầu vào cho phép cộng). Sử dụng phương thức asList, chúng ta chuyển đổi dữ liệu thành kiểu List, vì kiểu trả về của phương thức input là một Collection.

Code Dòng 30: Sử dụng @Thông số chú thích để tạo một tập hợp dữ liệu đầu vào để chạy thử nghiệm của chúng tôi.

Phương thức tĩnh được xác định bởi chú thích @Parameters trả về một Collection, trong đó mỗi phần tử trong Collection sẽ là dữ liệu đầu vào cho một lần lặp của bài kiểm tra. Hãy xem xét phần tử {1,2,3}. Ở đây:

  • firstNumber = 1
  • Số thứ hai = 2
  • expectedResult = 3

Ở đây, mỗi phần tử của mảng sẽ được truyền vào hàm tạo, từng phần tử một, khi lớp được khởi tạo nhiều lần. Do đó, năm mảng được khai báo trong ví dụ sẽ tạo ra năm lần chạy sau:

Lặp lại số đầu tiên số thứ hai Kết quả mong đợi Dòng điều khiển
[0] 1 2 3 Tổng của Numbers = : 3
[1] 11 22 33 Tổng của Numbers = : 33
[2] 111 222 333 Tổng của Numbers = : 333
[3] 10 9 19 Tổng của Numbers = : 19
[4] 100 9 109 Tổng của Numbers = : 109

Bước 5) Toàn bộ mã nguồn.

Hoàn chỉnh danh sách AirthematicTest bao gồm các lệnh import, hàm tạo, phương thức @Parameters và phương thức @Test.

Code Giải thích:

  • Code Dòng 25: Sử dụng chú thích @Before để thiết lập các tài nguyên (ở đây là Airthematic.class). Chú thích @Before được sử dụng ở đây để chạy trước mỗi trường hợp kiểm thử. Nó chứa điều kiện tiên quyết của bài kiểm thử.
  • Code Dòng 36: Sử dụng chú thích @Test để tạo bài kiểm tra của chúng ta.
  • Code Dòng 39: Tạo một câu lệnh khẳng định Để kiểm tra xem tổng của chúng ta có tương đương với những gì chúng ta mong đợi hay không.

Bước 6) Tạo một lớp chạy thử nghiệm để thực hiện kiểm thử tham số hóa:

Lớp TestRunner truyền lớp AirthematicTest.class cho JUnitCore.runClasses và lỗi in ấn

Code Giải thích:

  • Code Dòng 8: Khai báo phương thức main của lớp Test, phương thức này sẽ chạy chương trình của chúng ta. JUnit thử nghiệm.
  • Code Dòng 9: Thực hiện các trường hợp thử nghiệm bằng cách sử dụng JUnitCore.runClasses, phương thức này nhận tên lớp kiểm thử làm tham số (trong ví dụ này chúng ta đang sử dụng AirthematicTest.class).
  • Code Dòng 11: Xử lý kết quả bằng vòng lặp for và in ra kết quả thất bại.
  • Code Dòng 13: In ra kết quả thành công.

Đầu ra:

Đây là kết quả đầu ra, cho thấy bài kiểm tra đã thành công mà không có lỗi nào. trace, như được trình bày bên dưới. Lưu ý rằng JUnit Chế độ xem hiển thị một mục trên mỗi hàng dữ liệu thay vì một bài kiểm tra duy nhất:

Eclipse JUnit Xem báo cáo Chạy thành công 5/5 lần với 0 lỗi và 0 lần thất bại cho lớp tham số hóa

Hãy xem kết quả trên bảng điều khiển, hiển thị phép cộng hai số:

Eclipse in ra màn hình console một tổng của Numbers dòng cho mỗi trong năm hàng tham số

Kiểm thử tham số hóa trong JUnit 5 với @ParameterizedTest

Ví dụ trên được viết cho JUnit 4. JUnit 5 (Jupiter) loại bỏ hoàn toàn mô hình runner, do đó @RunWith(Parameterized.class), hàm tạo dữ liệu và các trường instance đều biến mất. JUnit Đoạn mã số 4 được hiển thị ở trên không phải là lỗi thời: nó vẫn chạy mà không thay đổi trên hệ thống. JUnit Nền tảng thông qua công cụ cũ. Tuy nhiên, các bài kiểm tra mới thường được viết bằng @ParameterizedTest.

Cần có hai thư viện phụ thuộc: junit-jupiter-api cho các chú thích kiểm thử và junit-jupiter-params để hỗ trợ tham số hóa. Nếu thiếu thành phần thứ hai, các chú thích nguồn sẽ không thể được giải quyết.

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

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;

class AirthematicTest {

    // one row per iteration, no constructor and no runner
    @ParameterizedTest(name = "{0} + {1} = {2}")
    @CsvSource({"1, 2, 3", "11, 22, 33", "111, 222, 333", "10, 9, 19", "100, 9, 109"})
    void sumOfTwoNumbers(int firstNumber, int secondNumber, int expectedResult) {
        assertEquals(expectedResult, new Airthematic().sum(firstNumber, secondNumber));
    }
}

Jupiter cung cấp một số nguồn lập luận khác nhau, và nguồn phù hợp phụ thuộc vào dạng dữ liệu:

Chú thích nguồn Đồ Sử dụng nó khi
@ValueSource Một cột duy nhất chứa các ký tự. Bài kiểm tra chỉ nhận đúng một đối số.
@CsvSource Các hàng nội tuyến được phân tách bằng dấu phẩy Các bảng nhỏ chứa số và chuỗi ký tự được đọc một cách gọn gàng trong tệp.
@CsvFileSource Các hàng được đọc từ tệp CSV trên classpath kiểm thử. Tập dữ liệu có kích thước lớn hoặc được lưu trữ bên ngoài mã nguồn.
@MethodSource Một factory tĩnh trả về một Stream các đối số. Cần có các đối tượng thực, giá trị được tính toán hoặc dữ liệu ngẫu nhiên.
@EnumSource Các hằng số của một kiểu liệt kê Mỗi giá trị enum đều phải được kiểm tra.

Có hai quy tắc mà hầu hết người mới bắt đầu thường mắc phải. Chú thích nguồn được đặt trên một phương thức `@Test` thông thường sẽ bị bỏ qua một cách âm thầm, vì vậy phương thức đó phải mang theo `@ParameterizedTest`. Và một giá trị rỗng không được trích dẫn trong `@CsvSource` sẽ được đọc là null, trong khi một giá trị rỗng được trích dẫn sẽ được đọc là một chuỗi rỗng.

JUnit 4 chú thích được sử dụng trong bài viết này được ánh xạ lên Jupiter như sau: @RunWith(Parameterized.class) trở thành @ParameterizedTest cộng với một chú thích nguồn, @Parameters trở thành @MethodSource hoặc @CsvSource, và @Before trở thành @BeforeEach. Danh sách đầy đủ được trình bày trong phần tiếp theo. JUnit chú thích hướng dẫn.

Ưu điểm và hạn chế của các bài kiểm tra tham số hóa

Việc tham số hóa không phải là miễn phí. Nó loại bỏ sự trùng lặp, nhưng cũng hạn chế cách viết bài kiểm thử, vì vậy cần hiểu rõ cả hai mặt trước khi chuyển đổi một bộ kiểm thử hiện có.

Ưu điểm

  • Less trùng lặp: Một phương pháp thay thế một khối các câu lệnh assert gần như giống hệt nhau, như ảnh chụp màn hình đầu tiên trong bài viết này cho thấy.
  • Bảo hiểm giá rẻ hơn: Việc thêm một trường hợp ngoại lệ chỉ tốn thêm một hàng dữ liệu thay vì toàn bộ một hàng mới. trường hợp thử nghiệm phương pháp.
  • Báo cáo chính xác: Mỗi lần lặp được báo cáo riêng biệt, do đó JUnit Chế độ xem này xác định chính xác hàng nào bị lỗi chứ không phải là một lỗi tổng hợp.
  • Dữ liệu tập trung: Các dữ liệu đầu vào được lưu trữ trong một phương thức duy nhất và sau đó có thể được chuyển sang tệp CSV hoặc factory mà không cần thay đổi các câu lệnh kiểm tra.

Hạn chế

  • Một hình thức khẳng định: Mỗi hàng đều chạy cùng một quy trình kiểm tra, vì vậy một trường hợp cần các kiểm tra khác nhau vẫn cần phương thức kiểm thử riêng.
  • Phạm vi cấp lớp trong JUnit 4: Trình chạy tham số hóa toàn bộ lớp, do đó các phương thức @Test không liên quan trong lớp đó cũng chạy một lần cho mỗi hàng.
  • Báo cáo không thể đọc được: Nếu không có mẫu tên, lỗi sẽ xuất hiện dưới dạng testAirthematicTest[3], không nói gì về dữ liệu bị lỗi.
  • Dữ liệu nội tuyến cồng kềnh: Các mảng lớn sẽ làm chật chội phần logic kiểm thử; hãy chuyển chúng sang `@CsvFileSource` hoặc `@MethodSource factory` thay thế.

Những lỗi thường gặp trong JUnit Kiểm thử tham số hóa

Hầu hết các lỗi liên quan đến tham số đều là lỗi khởi tạo phát sinh trước khi một câu lệnh kiểm tra nào đó được thực thi. Bảng dưới đây liệt kê các thông báo xuất hiện thường xuyên nhất và nguyên nhân gây ra chúng.

Tin nhắn Nguyên nhân Sửa chữa
Lớp kiểm thử chỉ nên có đúng một hàm tạo công khai. Lớp này không khai báo bất kỳ hàm tạo công khai nào, hoặc có đến hai hàm tạo công khai. Hãy giữ lại một hàm tạo công khai có các tham số khớp với các cột dữ liệu.
Không có phương thức tham số tĩnh công khai nào trên lớp Phương thức `@Parameters` không phải là phương thức tĩnh công khai, hoặc trả về kiểu dữ liệu sai. Khai báo nó là public static Collection và trả về Arrays.asList(…)
IllegalArgumentException: sai số lượng đối số Một hàng rộng hơn hoặc hẹp hơn danh sách tham số của hàm tạo. Đảm bảo mọi mảng trong Collection có cùng chiều rộng với hàm tạo.
Lỗi cấu hình: không có nhà cung cấp đối số Một bài kiểm tra Jupiter mang theo chú thích @ParameterizedTest mà không có chú thích nguồn. Thêm @ValueSource, @CsvSource, @CsvFileSource, @MethodSource hoặc @EnumSource
Chú thích nguồn dường như không có tác dụng gì. Phương thức được chú thích bằng @Test thay vì @ParameterizedTest Thay thế `@Test` bằng `@ParameterizedTest` và nhập `junit-jupiter-params`.

Một cạm bẫy khác nữa là trạng thái được chia sẻ. Bởi vì JUnit Tạo một thể hiện mới cho mỗi hàng, bất kỳ thứ gì được lưu giữ trong trường tĩnh đều tồn tại sau mỗi lần lặp và giá trị được ghi bởi hàng [0] có thể âm thầm thay đổi kết quả của hàng [4]. Giữ trạng thái trên mỗi hàng trong các trường thể hiện và đặt lại các tài nguyên được chia sẻ trong phương thức @Before hoặc @BeforeEach. Hướng dẫn chung về việc cô lập các bài kiểm tra được đề cập trong kiểm tra đơn vị hướng dẫn.

Câu Hỏi Thường Gặp

TestNG Cung cấp các hàng thông qua phương thức `@DataProvider` được tham chiếu trong mỗi phương thức kiểm thử, do đó các bài kiểm thử không liên quan trong cùng lớp sẽ không bị ảnh hưởng. JUnit 4 tham số hóa toàn bộ lớp thông qua trình chạy của nó. JUnit Mục 5 thu hẹp khoảng cách đó với @ParameterizedTest cho từng phương thức.

Vâng. JUnit 4 chấp nhận @Parameters(name = “{index}: sum({0},{1})={2}”) và Jupiter chấp nhận @ParameterizedTest(name = “…”). Các phần giữ chỗ được thay thế trong quá trình chạy, vì vậy báo cáo lỗi sẽ nêu tên hàng gây lỗi thay vì chỉ hiển thị một chỉ mục đơn thuần.

Vâng. JUnit 4 hỗ trợ @Parameter(0) và @Parameter(1) trên các trường không tĩnh công khai và lớp sau đó dựa vào hàm tạo mặc định. Việc kết hợp tiêm trường với hàm tạo dữ liệu sẽ gây ra lỗi chỉ có một hàm tạo công khai.

JUnit Mục 4 chỉ cần tệp tin junit, vì trình chạy tham số hóa được tích hợp sẵn trong đó. JUnit Mục 5 yêu cầu junit-jupiter-params cùng với junit-jupiter-api; nếu thiếu thành phần đó, @ParameterizedTest và mọi chú thích nguồn đều không thể được giải quyết.

Jupiter cung cấp @CsvFileSource(resources = “/data.csv”, numLinesToSkip = 1), phương thức này đọc các hàng từ classpath kiểm thử. JUnit Mục 4 không có chức năng tương đương tích hợp sẵn, vì vậy phương thức @Parameters phải tự mở và phân tích cú pháp tệp trước khi trả về Collection.

In JUnit 4. Có thể, nhưng trình chạy sẽ tham số hóa toàn bộ lớp, vì vậy mỗi phương thức sẽ chạy một lần cho mỗi hàng dữ liệu. Jupiter tham số hóa từng phương thức riêng lẻ, vì vậy các phương thức @Test thông thường trong cùng một lớp vẫn thực thi chính xác một lần.

Các trợ lý AI đọc chữ ký phương thức và đề xuất các hàng giới hạn như giá trị bằng không, âm, tối đa và tràn số mà bảng viết tay thường bỏ sót. RevHãy xem xét mọi kết quả dự kiến ​​được tạo ra, bởi vì mô hình có thể tạo ra một hàng hợp lý nhưng lại có câu trả lời sai.

Trợ lý GitHub Tạo giàn giáo nhanh chóng nhưng thường bị trộn lẫn. JUnit 4 và Jupiter import, và đôi khi để lại chú thích nguồn trên một phương thức @Test thông thường. Hãy kiểm tra các import trước khi chạy bộ kiểm thử.

Tóm tắt bài viết này với: