JUnit 5: Làm thế nào để khẳng định một ngoại lệ được ném ra?


214

Có cách nào tốt hơn để khẳng định rằng một phương thức đưa ra một ngoại lệ trong JUnit 5 không?

Hiện tại, tôi phải sử dụng @Rule để xác minh rằng thử nghiệm của tôi có ngoại lệ, nhưng điều này không hiệu quả đối với các trường hợp tôi mong đợi nhiều phương pháp đưa ra ngoại lệ trong thử nghiệm của mình.


1
bạn có thể muốn kiểm tra AssertJ để kiểm tra ngoại lệ tại nó linh hoạt hơn JUnit5
user1075613

Câu trả lời:


321

Bạn có thể sử dụng assertThrows(), cho phép bạn kiểm tra nhiều ngoại lệ trong cùng một bài kiểm tra. Với sự hỗ trợ cho lambdas trong Java 8, đây là cách chuẩn để kiểm tra các ngoại lệ trong JUnit.

Theo các tài liệu JUnit :

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

@Test
void exceptionTesting() {
    MyException thrown = assertThrows(
           MyException.class,
           () -> myObject.doThing(),
           "Expected doThing() to throw, but it didn't"
    );

    assertTrue(thrown.getMessage().contains("Stuff"));
}

11
Từ một trường học cũ "Tôi không biết nhiều về Junit5 và có lẽ không đủ về Java8" ... điều này có vẻ khá kỳ quái. Bạn có phiền thêm một số giải thích thêm; như "phần nào trong đó có 'mã sản xuất' thực tế đang được thử nghiệm ... đáng lẽ phải ném"?
GhostCat

1
() -> chỉ đến một biểu thức lambda chấp nhận các đối số bằng không. Do đó, "mã sản xuất" dự kiến ​​sẽ ném ngoại lệ nằm trong khối mã được trỏ đến (nghĩa là throw new...câu lệnh trong dấu ngoặc nhọn).
Sam Brannen

1
Thông thường, biểu thức lambda sẽ tương tác với đối tượng được thử nghiệm (SUT). Nói cách khác, trực tiếp ném một ngoại lệ như trên chỉ nhằm mục đích trình diễn.
Sam Brannen

1
Có vẻ như kỳ vọng là không được chấp nhận. Tài liệu nói để sử dụng assertThrows () thay vì bây giờ.
depsypher 14/03/2017

5
Kể từ phiên bản 5.0.0-M4, mong đợi không còn nữa. Chỉ khẳng định các mũi tên được cho phép. Xem github.com/junit-team/junit5/blob/master/documentation/src/docs/... : 'Assertions.expectThrows phản xoá () phương pháp có lợi cho Assertions.assertThrows ()'
gil.fernandes

91

Trong Java 8 và JUnit 5 (Sao Mộc), chúng ta có thể khẳng định các ngoại lệ như sau. Sử dụngorg.junit.jupiter.api.Assertions.assertThrows

công khai tĩnh <T extends throwable> T assertThrows (Class <T> kỳ vọng loại, thực thi thực thi)

Xác nhận rằng việc thực thi tệp thực thi được cung cấp sẽ ném ngoại lệ của Loại dự kiến ​​và trả về ngoại lệ.

Nếu không có ngoại lệ được ném, hoặc nếu một ngoại lệ của một loại khác được ném, phương pháp này sẽ thất bại.

Nếu bạn không muốn thực hiện kiểm tra bổ sung trong trường hợp ngoại lệ, chỉ cần bỏ qua giá trị trả về.

@Test
public void itShouldThrowNullPointerExceptionWhenBlahBlah() {
    assertThrows(NullPointerException.class,
            ()->{
            //do whatever you want to do here
            //ex : objectName.thisMethodShoulThrowNullPointerExceptionForNullParameter(null);
            });
}

Cách tiếp cận đó sẽ sử dụng Giao diện chức năng Executabletrong org.junit.jupiter.api.

Tham khảo :


1
Lên đỉnh với cái này! Đây là câu trả lời tốt nhất cho đến nay là cập nhật nhất với JUnit 5. Ngoài ra, IntelliJ đang ngưng tụ lambda hơn nữa nếu chỉ có một dòng cho Lambda:assertThrows(NoSuchElementException.class, myLinkedList::getFirst);
anon58192932

26

Họ đã thay đổi nó trong JUnit 5 (dự kiến: UnlimitedArgumentException, thực tế: phương thức được gọi) và mã trông giống như thế này:

@Test
public void wrongInput() {
    Throwable exception = assertThrows(InvalidArgumentException.class,
            ()->{objectName.yourMethod("WRONG");} );
}

21

Bây giờ Junit5 cung cấp một cách để khẳng định các ngoại lệ

Bạn có thể kiểm tra cả ngoại lệ chung và ngoại lệ tùy chỉnh

Một kịch bản ngoại lệ chung:

ExpectGeneralException.java

public void validateParameters(Integer param ) {
    if (param == null) {
        throw new NullPointerException("Null parameters are not allowed");
    }
}

ExpectGeneralExceptionTest.java

@Test
@DisplayName("Test assert NullPointerException")
void testGeneralException(TestInfo testInfo) {
    final ExpectGeneralException generalEx = new ExpectGeneralException();

     NullPointerException exception = assertThrows(NullPointerException.class, () -> {
            generalEx.validateParameters(null);
        });
    assertEquals("Null parameters are not allowed", exception.getMessage());
}

Bạn có thể tìm thấy một mẫu để kiểm tra CustomException tại đây: xác nhận mẫu mã ngoại lệ

ExpectCustomException.java

public String constructErrorMessage(String... args) throws InvalidParameterCountException {
    if(args.length!=3) {
        throw new InvalidParameterCountException("Invalid parametercount: expected=3, passed="+args.length);
    }else {
        String message = "";
        for(String arg: args) {
            message += arg;
        }
        return message;
    }
}

ExpectCustomExceptionTest.java

@Test
@DisplayName("Test assert exception")
void testCustomException(TestInfo testInfo) {
    final ExpectCustomException expectEx = new ExpectCustomException();

     InvalidParameterCountException exception = assertThrows(InvalidParameterCountException.class, () -> {
            expectEx.constructErrorMessage("sample ","error");
        });
    assertEquals("Invalid parametercount: expected=3, passed=2", exception.getMessage());
}

1
Không có sự khác biệt trong cách JUnit xử lý các ngoại lệ tích hợp và tùy chỉnh.
raindev

9

Tôi nghĩ rằng đây là một ví dụ đơn giản hơn

List<String> emptyList = new ArrayList<>();
Optional<String> opt2 = emptyList.stream().findFirst();
assertThrows(NoSuchElementException.class, () -> opt2.get());

Gọi get()vào một tùy chọn có chứa một trống ArrayListsẽ ném a NoSuchElementException. assertThrowstuyên bố ngoại lệ dự kiến ​​và cung cấp một nhà cung cấp lambda (không có đối số và trả về giá trị).

Cảm ơn @prime cho câu trả lời của anh ấy mà tôi hy vọng được xây dựng trên.


1
phương thức assertThrowstrả về ngoại lệ ném. Vì vậy, bạn có thể làm như NoSuchElementException e = assertThrows(NoSuchElementException.class, () -> opt2.get());sau đó bên dưới bạn có thể thực hiện bất kỳ loại xác nhận nào về đối tượng ngoại lệ bạn muốn.
Thuyền trưởng Man

8

Bạn có thể sử dụng assertThrows(). Ví dụ của tôi được lấy từ các tài liệu http://junit.org/junit5/docs/civerse/user-guide/

import org.junit.jupiter.api.Test;

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

....

@Test
void exceptionTesting() {
    Throwable exception = assertThrows(IllegalArgumentException.class, () -> {
        throw new IllegalArgumentException("a message");
    });
    assertEquals("a message", exception.getMessage());
}

2

Một lót thậm chí đơn giản hơn. Không có biểu thức lambda hoặc dấu ngoặc nhọn cần thiết cho ví dụ này bằng cách sử dụng Java 8 và JUnit 5

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

@Test
void exceptionTesting() {

    assertThrows(MyException.class, myStackObject::doStackAction, "custom message if assertion fails..."); 

// note, no parenthesis on doStackAction ex ::pop NOT ::pop()
}

1

Trên thực tế tôi nghĩ rằng có một lỗi trong tài liệu cho ví dụ cụ thể này. Phương thức được dự định là kỳ vọng.

public static void assertThrows(
public static <T extends Throwable> T expectThrows(

3
"Đã xóa phương thức Assertions.recectThrows () không dùng cho Assertions.assertThrows ()."
Martin Schröder

Đối với Junit 5, hãy đảm bảo rằng đó là từ org.junit.jupiter.api.Assertions không phải org.testng.Assert. Dự án của chúng tôi có cả Junit và TestNG, và tôi tiếp tục nhận được assertThrows trả về lỗi void cho đến khi tôi thay đổi nó thành assertExpects. Hóa ra tôi đang sử dụng org.testng.Assert.
barryku

-5

Đây là một cách dễ dàng.

@Test
void exceptionTest() {

   try{
        model.someMethod("invalidInput");
        fail("Exception Expected!");
   }
   catch(SpecificException e){

        assertTrue(true);
   }
   catch(Exception e){
        fail("wrong exception thrown");
   }

}

Nó chỉ thành công khi Ngoại lệ bạn mong đợi được ném.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.