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.
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:
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.
Bước 2) Tạo một lớp kiểm thử có tham số.
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.
Bước 4) Tạo một phương thức tĩnh tạo và trả về dữ liệu thử nghiệm.
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.
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:
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:
Hãy xem kết quả trên bảng điều khiển, hiển thị phép cộng hai 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.









