JUnit 5: Как утверждать, исключение брошено?


215

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

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


1
вам может быть интересно проверить AssertJ для проверки исключений в нем более гибким, чем JUnit5
user1075613

Ответы:


325

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

Согласно документам 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
Из старой школы "Я не знаю много о Junit5 и, возможно, недостаточно о Java8" ... это выглядит довольно странно. Не могли бы вы добавить еще несколько объяснений; например, «какая часть там является тестируемым« рабочим кодом »... который должен был бы выдать»?
GhostCat

1
() -> указывает на лямбда-выражение, которое принимает нулевые аргументы. Таким образом, «производственный код» , который , как ожидается , бросить исключение в блоке кода указывал на (то есть, в throw new...заявлении в фигурных скобках).
Сэм Браннен

1
Обычно лямбда-выражение взаимодействует с испытуемым (SUT). Другими словами, прямое генерирование исключения, как описано выше, просто для демонстрационных целей.
Сэм Браннен

1
Похоже, waitThrows устарела. Документы говорят использовать assertThrows () вместо этого сейчас.
Депсифер

5
Начиная с версии 5.0.0-M4, ожидаемые версии больше не доступны. Разрешено только assertThrows . См. Github.com/junit-team/junit5/blob/master/documentation/src/docs/… : «Удален устаревший метод Assertions.expectThrows () в пользу Assertions.assertThrows ()»
gil.fernandes

91

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

public static <T extends Throwable> T assertThrows (класс <T> Ожидаемый тип, исполняемый файл)

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

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

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

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

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

См .:


1
На вершину с этим! На данный момент это лучший ответ, который является самым актуальным с JUnit 5. Кроме того, IntelliJ сокращает лямбду еще больше, если есть только одна линия к assertThrows(NoSuchElementException.class, myLinkedList::getFirst);
лямбде

26

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

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

21

Теперь 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 здесь: пример кода исключения assert

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
Нет никакой разницы в том, как JUnit обрабатывает встроенные и пользовательские исключения.
raindev

9

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

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

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

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


1
метод assertThrowsвозвращает выброшенное исключение. Таким образом, вы можете делать NoSuchElementException e = assertThrows(NoSuchElementException.class, () -> opt2.get());то же самое, что и ниже, вы можете делать любые утверждения для объекта исключения, который вы хотите.
Капитан Мэн

8

Вы можете использовать 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());
}

2

Еще более простой лайнер. Никакие лямбда-выражения или фигурные скобки не требуются для этого примера с использованием 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()
}

1

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

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

3
"Удален устаревший метод Assertions.expectThrows () в пользу Assertions.assertThrows ()."
Мартин Шредер,

Для Junit 5 убедитесь, что он из org.junit.jupiter.api.Assertions, а не из org.testng.Assert. В наш проект включены как Junit, так и TestNG, и я продолжал получать assertThrows, возвращающий void error, пока не изменил его на assertExpected. Оказалось, что я использую org.testng.Assert.
Баррику

-5

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

@Test
void exceptionTest() {

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

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

}

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.