Есть ли лучший способ утверждать, что метод вызывает исключение в JUnit 5?

В настоящее время мне нужно использовать @Rule, чтобы убедиться, что мой тест вызывает исключение, но это не работает в тех случаях, когда я ожидаю, что несколько методов вызовут исключения в моем тесте.

Ответы (10)

Вы можете использовать assertThrows (), что позволяет тестировать несколько исключений в рамках одного теста. Благодаря поддержке лямбда-выражений в Java 8 это канонический способ проверки исключений в JUnit.

Согласно документации JUnit:

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

@Контрольная работа
void exceptionTesting () {
    MyException брошено = assertThrows (
           MyException.class,
           () -> myObject.doThing (),
           "Ожидалось, что doThing () выбросит, но этого не произошло"
    );

    assertTrue (thrown.getMessage (). contains ("Материал"));
}

Еще проще one liner. В этом примере с использованием Java 8 и 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()
}

Вот простой способ.

@Test
void exceptionTest() {

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

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

}

Успешно, только если выбрано ожидаемое исключение.

В Java 8 и JUnit 5 (Jupiter) мы можем утверждать исключения следующим образом. Использование org.junit.jupiter.api.Assertions.assertThrows

public static T assertThrows (Class expectedType, Исполняемый исполняемый файл)

Утверждает, что выполнение предоставленного исполняемого файла вызывает исключение ожидаемого типа и возвращает исключение.

Если не генерируется исключение или выбрасывается исключение другого типа, этот метод завершится ошибкой.

Если вы не хотите выполнять дополнительные проверки экземпляра исключения, просто проигнорируйте возвращаемое значение.

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

Этот подход будет использовать Функциональный интерфейс Исполняемый в org.junit.jupiter.api.

Обратитесь:

Теперь Junit5 предоставляет возможность утверждать исключения

Вы можете тестировать как общие исключения, так и настраиваемые исключения

Общий сценарий исключения:

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());
}

Вы можете найти образец для тестирования CustomException здесь: пример кода утверждения исключения

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());
}

Они изменили его в JUnit 5 (ожидалось: InvalidArgumentException, фактическое: вызванный метод), и код выглядит следующим образом:

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

Вы можете использовать assertThrows (). Мой пример взят из документации http://junit.org/junit5/docs/current/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());
}

TL; DR: Если вы используете версию JUnit 5.8.0+, вы можете использовать assertThrowsExactly (), чтобы соответствовать точному типу исключения.

assertThrowsExactly(FileNotFoundException.class, () -> service.blah());

Вы можете использовать assertThrows (), но с assertThrows ваше утверждение пройдет, даже если выброшенное исключение имеет дочерний тип.

Это потому, что JUnit 5 проверяет тип исключения, вызывая Class.isIntance (..), Class.isInstance (..) вернет true, даже если выброшенное исключение детского типа.

Обходной путь для этого - утверждать в классе:

Throwable throwable =  assertThrows(Throwable.class, () -> {
    service.readFile("sampleFile.txt");
});
assertEquals(FileNotFoundException.class, throwable.getClass());

На самом деле я думаю, что в документации для этого конкретного примера есть ошибка. Предполагаемый метод - expectThrows

.
public static void assertThrows(
public static  T expectThrows(

Думаю, это еще более простой пример

Список  emptyList = новый ArrayList <> ();
Необязательный  opt2 = emptyList.stream (). FindFirst ();
assertThrows (NoSuchElementException.class, () -> opt2.get ());

Вызов get () для необязательного элемента, содержащего пустой ArrayList, вызовет исключение NoSuchElementException.assertThrows объявляет ожидаемое исключение и предоставляет поставщика лямбда (не принимает аргументов и возвращает значение).

Спасибо @prime за его ответ, который я, надеюсь, уточнил.

2022 WebDevInsider