JUnit Kiểm tra ngoại lệ dự kiến: @Test(expected)

⚡ Tóm tắt thông minh

JUnit Kiểm thử ngoại lệ xác nhận rằng một phương thức ném ra lỗi mà nó được cho là sẽ ném ra, bằng cách sử dụng tham số expected tùy chọn của chú thích @Test trong JUnit 4 và phương thức assertThrows trong JUnit 5.

  • 🔘 Mục đích: Chứng minh rằng dữ liệu đầu vào không hợp lệ sẽ gây ra ngoại lệ đã được ghi nhận thay vì một câu trả lời sai không được báo lỗi.
  • ☑️ Cú pháp: @Test(expected = ArithmeticException.class) chỉ được chấp nhận khi đúng loại ngoại lệ đó được ném ra.
  • Ví dụ: JUnitThông báo chia cho 0, và AirthematicTest dự kiến ​​sẽ trả về lỗi ArithmeticException.
  • 🧪 thay thế: Khối try theo sau là fail() cho phép bạn kiểm tra ngoại lệ đã bắt được trước khi khẳng định kết quả.
  • 🛠️ JUnit 5: Phương thức assertThrows trả về ngoại lệ đã bắt được, vì vậy thông báo và nguyên nhân cũng có thể được xác nhận.
  • 📌 Cạm bẫy: Tham số mong đợi vẫn được truyền đi bất kể ngoại lệ xảy ra ở đâu, điều này có thể che giấu lỗi trong mã thiết lập.

JUnit Kiểm tra ngoại lệ dự kiến ​​bằng cách sử dụng tham số @Test(expected)

JUnit cung cấp cơ sở vật chất cho tracxử lý ngoại lệ và kiểm tra xem mã có ném ra ngoại lệ dự kiến ​​hay không.

JUnit Mục 4 cung cấp một cách dễ dàng và dễ đọc để kiểm thử ngoại lệ. Bạn có thể sử dụng:

  • Tham số tùy chọn (được mong đợi) của Chú thích @Test
  • Đến tracVới thông tin này, có thể sử dụng hàm “fail()”.

Trong khi thử nghiệm Nếu là trường hợp ngoại lệ, bạn cần đảm bảo rằng lớp ngoại lệ mà bạn cung cấp trong tham số tùy chọn đó là đúng. Chú thích @Test Đây chính là ngoại lệ mà phương thức thực sự ném ra. Điều này là do bạn đang mong đợi một ngoại lệ từ phương thức mà bạn đang... kiểm tra đơn vị; nếu không thì của chúng ta JUnit thử nghiệm sẽ thất bại.

Ví dụ: @Test(expected = IllegalArgumentException.class)

Bằng cách sử dụng tham số “expected”, bạn có thể chỉ định tên ngoại lệ mà bài kiểm tra của chúng ta có thể ném ra. Trong ví dụ trên, bạn đang sử dụng “Ngoại lệ Đối số bất hợp pháp"Lỗi này sẽ được báo cáo trong bài kiểm tra nếu nhà phát triển sử dụng một đối số không được phép."

Ví dụ sử dụng @Test(expected)

Hãy cùng tìm hiểu về kiểm thử ngoại lệ bằng cách tạo ra một ví dụ. Java lớp có một phương thức ném ra một ngoại lệ ngoại lệBạn sẽ xử lý và kiểm tra nó trong một lớp kiểm thử. Hãy xem xét JUnitTệp Message.java có một phương thức thực hiện phép toán. Phép chia ở dòng 14 chia cho 0, vì vậy phương thức luôn ném ra ngoại lệ “ArithmeticException”. Xem bên dưới:

JUnitLớp tin nhắn trong Eclipse với thông báo lỗi chia cho 0 ở dòng 14

package guru99.junit;

public class JUnitMessage{

	private String message;

	public JUnitMessage(String message) {
		this.message = message;
	}

public void printMessage(){

	System.out.println(message); 
	int divide=1/0;

}

public String printHiMessage(){ 

	message="Hi!" + message;
	
	System.out.println(message);

	return message;
}

}

Code Giải thích:

  • Code Dòng 7: Tạo một hàm tạo được tham số hóa với việc khởi tạo trường.
  • Code Dòng 11-14: Xây dựng phương pháp cho phép toán.
  • Code Dòng 18: Tạo một phương pháp khác để in tin nhắn.
  • Code Dòng 20: Tạo một chuỗi mới để in một tin nhắn.
  • Code Dòng 22: In thông báo mới được tạo ở dòng 20.

Chúng ta hãy tạo một lớp kiểm thử cho đoạn mã trên. Java lớp để xác minh ngoại lệ.

Xem bên dưới lớp kiểm thử thực hiện kiểm thử đơn vị ngoại lệ (ở đây là ArithmeticException) được ném ra từ đoạn mã trên. Java lớp học:

AirthematicTest.java

Ảnh chụp màn hình bên dưới hiển thị cùng một bài kiểm tra trong trình chỉnh sửa, trong đó tệp được lưu dưới dạng AirthematicTest1, với tham số mong đợi được đánh dấu ở dòng 13:

Lớp AirthematicTest1 trong Eclipse với @Test(expected = ArithmeticException.class) được đánh dấu trên dòng 13

package guru99.junit;

import static org.junit.Assert.assertEquals;

import org.junit.Test;

public class AirthematicTest {

	public String message = "Saurabh";
	
	JUnitMessage junitMessage = new JUnitMessage(message);
	
	@Test(expected = ArithmeticException.class)
	public void testJUnitMessage(){

		System.out.println("Junit Message is printing ");
		junitMessage.printMessage();

	}

	@Test
	public void testJUnitHiMessage(){ 
		message="Hi!" + message;
		System.out.println("Junit Message is printing ");
		assertEquals(message, junitMessage.printHiMessage());
	
	}
}

Code Giải thích:

  • Code Dòng 13: Sử dụng chú thích `@Test` để tạo bài kiểm tra. Khi bạn thực thi phương thức của lớp ở trên, nó sẽ gọi một phép toán. Ở đây, ngoại lệ `ArithmeticException` được mong đợi, vì vậy bạn liệt kê nó ra như một tham số trong `@Test`.
  • Code Dòng 17: Gọi hàm printMessage() từ JUnitTin nhắn.java.
  • Code Dòng 21-22: Tạo thêm một phương thức kiểm thử khác để kiểm tra thông báo "Hi", lần này không có tham số mong đợi.

Lớp này chứa hai phương thức kiểm thử, vì vậy một lần chạy sẽ thực thi cả hai: một phương thức dự đoán sẽ xảy ra ngoại lệ ArithmeticException và một phương thức khẳng định dựa trên chuỗi được trả về.

Lưu ý: Ví dụ này xuất hiện dưới ba tên khác nhau trong tài liệu gốc — danh sách gọi lớp là AirthematicTest, ảnh chụp màn hình trình chỉnh sửa hiển thị AirthematicTest1, và kết quả hiển thị là JunitTestExample. Mã nguồn giống hệt nhau trong mỗi trường hợp; chỉ khác nhau ở tên tệp.

Chúng ta hãy thực hiện và kiểm chứng kết quả. JUnit Xem báo cáo bên dưới về quá trình hoạt động của... JunitTestExample.java.

Đầ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. tracnhư được nêu bên dưới:

Eclipse JUnit Xem báo cáo: Chạy 2/2 với không lỗi và không thất bại nào cho JunitTestExample

Cả hai phương pháp đều thành công. Phương pháp đầu tiên thành công vì ngoại lệ ArithmeticException mà nó khai báo đã xảy ra, và phương pháp thứ hai thành công vì chuỗi trả về khớp với kết quả. Nếu phép chia không bao giờ gây ra ngoại lệ, JUnit Phương pháp đầu tiên sẽ thất bại với thông báo “Expected exception: java.lang.ArithmeticException”.

Ba cách để kiểm tra một ngoại lệ trong JUnit 4

Tham số mong đợi là tham số ngắn nhất trong ba tham số. JUnit Có 4 thành ngữ, nhưng không phải lúc nào cũng chọn đúng. Bảng so sánh chúng dựa trên hai câu hỏi quyết định sự lựa chọn: bạn có thể khẳng định thông điệp đó không, và bạn có biết dòng nào đã được sử dụng không?

Phương pháp tiếp cận Thông điệp khẳng định điều đó? Ghim vạch ném? Tốt nhất cho
@Test(expected = X.class) Không Không — bất kỳ dòng nào trong phương thức đều có thể gây ra lỗi. Các bài kiểm tra ngắn, trong đó chỉ loại ngoại lệ là quan trọng.
thử / thất bại() / bắt Vâng, bên trong khối bắt giữ Đúng vậy — chỉ những cuộc gọi được bảo vệ mới được theo dõi. Các bài kiểm tra phải xem xét thông điệp hoặc nguyên nhân.
@Rule ExpectedException Vâng, thông qua expectMessage(). Không Các bộ ứng dụng cũ đã được xây dựng dựa trên các quy tắc.

Cấu trúc hàm fail() được đề cập trong phần giới thiệu trông như thế này. Nếu lệnh gọi không gây ra lỗi, hàm fail() sẽ chạy và bài kiểm tra sẽ báo cáo thông báo mà bạn đã viết:

@Test
public void testDivideByZero() {
    try {
        junitMessage.printMessage();
        fail("Expected an ArithmeticException");
    } catch (ArithmeticException e) {
        assertEquals("/ by zero", e.getMessage());
    }
}

Quy tắc ExpectedException nằm giữa hai quy tắc kia. Nó đã bị loại bỏ trong... JUnit 4.13 ủng hộ phương thức assertThrows được mô tả tiếp theo, vì vậy mới JUnit 4 bài kiểm tra không nên áp dụng nó.

Cách kiểm thử ngoại lệ trong JUnit 5 với assertThrows()

JUnit Mục 5 loại bỏ hoàn toàn tham số dự kiến ​​khỏi @Test. Jupiter cung cấp assertThrows()Phương thức này nhận vào lớp ngoại lệ và một hàm lambda chứa đoạn mã cần kiểm thử. Nó trả về ngoại lệ đã bắt được, do đó thông báo, nguyên nhân và bất kỳ trường tùy chỉnh nào đều có thể được xác nhận sau đó.

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

public class AirthematicJupiterTest {

    JUnitMessage junitMessage = new JUnitMessage("Saurabh");

    @Test
    public void testJUnitMessage() {
        ArithmeticException thrown = assertThrows(
                ArithmeticException.class,
                () -> junitMessage.printMessage());
        assertEquals("/ by zero", thrown.getMessage());
    }
}

Ba người có liên quan khẳng định Hoàn thiện gia đình:

  • assertThrows Chấp nhận kiểu ngoại lệ hoặc bất kỳ lớp con nào của nó.
  • assertThrowsExactly Từ chối một lớp con, vì vậy chỉ kiểu được đặt tên mới được chấp nhận.
  • assertDoesNotThrow Điều này thể hiện kỳ ​​vọng ngược lại, rằng khối lệnh sẽ được hoàn thành một cách trơn tru.

JUnit Đoạn mã số 4 trên trang này vẫn đang chạy trên... JUnit Nền tảng được xây dựng thông qua công cụ cũ, vì vậy không cần phải viết lại bất cứ thứ gì ở trên để dự án tiếp tục hoạt động trong quá trình chuyển đổi.

Những lỗi thường gặp khi kiểm thử ngoại lệ trong JUnit

Các bài kiểm tra ngoại lệ thất bại theo một số ít cách dễ nhận biết. Mỗi hàng nêu rõ triệu chứng, nguyên nhân và cách khắc phục.

Triệu chứng Nguyên nhân Sửa chữa
Ngoại lệ dự kiến: java.lang.ArithmeticException Phương pháp này hoàn thành mà không gây ra lỗi. Hãy kiểm tra xem dữ liệu đầu vào có thực sự không hợp lệ hay không, sau đó chạy lại.
Bài kiểm tra đạt nhưng lại xuất ra dòng sai. Tham số mong đợi giám sát toàn bộ phương thức, bao gồm cả thiết lập. Di chuyển phần thiết lập ra ngoài, hoặc chuyển sang sử dụng assertThrows xung quanh một lệnh gọi duy nhất.
Loại ngoại lệ chưa được xử lý trong trình soạn thảo Một ngoại lệ đã được kiểm tra được ném ra nhưng chưa bao giờ được khai báo. Thêm từ khóa `throws` vào chữ ký phương thức kiểm thử.
Bài kiểm tra thành công trên một lớp con mà bạn không hề dự định. Phương thức assertThrows chấp nhận các lớp con của kiểu được đặt tên. Hãy sử dụng assertThrowsExactly để đảm bảo khớp kiểu dữ liệu chính xác.
expected không phải là một thuộc tính hợp lệ Bài kiểm tra được biên dịch dựa trên chú thích @Test của Jupiter. Nhập org.junit.Test cho JUnit 4, hoặc chuyển sang assertThrows.

Dòng cuối cùng là dòng khiến hầu hết mọi người gặp khó khăn trong quá trình chuyển đổi, bởi vì cả hai chú thích đều được đặt tên là @Test và chỉ có thao tác nhập mới phân biệt được chúng. Giữping một JUnit phiên bản mỗi trường hợp thử nghiệm Lớp học này tránh được toàn bộ loại vấn đề.

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

Tham số mong đợi không thể kiểm tra thông báo. Hãy bọc lệnh gọi trong khối try, gọi fail() ngay sau đó và khẳng định getMessage() bên trong khối catch. JUnit Mục 5 làm cho việc này đơn giản hơn vì assertThrows trả về ngoại lệ đã bắt được.

JUnit Bài kiểm tra thất bại và báo cáo "Ngoại lệ dự kiến" theo sau là tên lớp bạn đã đặt. Không có thông tin nào khác được báo cáo, vì vậy một bài kiểm tra không bao giờ ném ngoại lệ trông giống hệt như một bài kiểm tra mà mã sản xuất đã âm thầm thay đổi hành vi.

Các trợ lý AI đọc một phương thức, liệt kê các đầu vào dẫn đến từng câu lệnh `throw` và soạn thảo một bài kiểm tra cho mỗi nhánh. Hãy coi đầu ra như một điểm khởi đầu: trợ lý suy luận loại ngoại lệ từ mã, vì vậy một lỗi `throw` sai sẽ được sao chép chính xác vào bài kiểm tra.

Phi công phụ Nó tuân theo bất kỳ kiểu nào đã tồn tại trong tệp, vì vậy một dự án hỗn hợp sẽ nhận được một sự kết hợp. Hãy kiểm tra dòng nhập khẩu trước khi chấp nhận đề xuất, vì org.junit.Test và org.junit.jupiter.api.Test trông giống hệt nhau trong trình soạn thảo.

Nó vẫn tồn tại, nhưng đã bị loại bỏ từ lâu. JUnit Phiên bản 4.13 chưa từng được chuyển đổi sang Jupiter. Các bộ kiểm thử hiện có có thể giữ nguyên; các bài kiểm thử mới nên sử dụng assertThrows, dễ đọc hơn và không cần trường quy tắc công khai.

Đúng vậy. Tham số lambda là một Executable, được khai báo là ném ra Throwable, vì vậy một ngoại lệ được kiểm tra không cần mệnh đề throws trong chính phương thức kiểm thử. Điều tương tự cũng đúng với... JUnit 4. Thành ngữ "cố gắng bắt lấy".

`assertThrowsExactly` chấp nhận bất kỳ lớp con nào của kiểu bạn chỉ định, vì vậy việc mong đợi `RuntimeException` cũng sẽ truyền cả `NullPointerException`. Hãy sử dụng `assertThrowsExactly` khi lớp chính xác là quan trọng, hoặc chỉ định kiểu hẹp nhất mà bạn thực sự mong đợi.

Chỉ khi ngoại lệ là một phần của điều khoản hợp lệ thì mới áp dụng.tract. Việc kiểm thử một ngoại lệ mà phương thức này không bao giờ đảm bảo sẽ không gây ra lỗi khóa trong các trường hợp ngoại lệ ngoài ý muốn và làm cho việc tái cấu trúc trở nên khó khăn hơn, điều này làm mất đi mục đích của việc kiểm thử.

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