5 червня: Як стверджувати, що виняток кидається?


214

Чи є кращий спосіб стверджувати, що метод кидає виняток у JUnit 5?

На даний момент я маю використовувати @Rule для того, щоб перевірити, що мій тест кидає виняток, але це не працює для тих випадків, коли я очікую, що в моєму тесті кілька методів видають винятки.


1
можливо, вам буде цікаво перевірити AssertJ на перевірку винятків у ньому більш гнучко, ніж у JUnit5
user1075613,

Відповіді:


323

Ви можете використовувати 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
Схоже, очікуванняЗростання застаріло. Документи кажуть, що замість цього зараз використовувати assertThrows ().
депсифер

5
Станом на версію 5.0.0-M4 очікуйте, що розростання більше не доступні. Дозволено лише стверджуватизростання . Див. Github.com/junit-team/junit5/blob/master/documentation/src/docs/… : "Видалено застарілий метод Assertions.expectThrows () на користь
Assertions.assertThrows

91

У Java 8 та JUnit 5 (Юпітер) ми можемо стверджувати про винятки наступним чином. Використанняorg.junit.jupiter.api.Assertions.assertThrows

загальнодоступна статична <T поширюється 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 тут: стверджувати зразок коду виключення

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буде виведено a 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 ()."
Мартін Шредер

Для 5 червня переконайтесь, що це від org.junit.jupiter.api.Assertions not org.testng.Assert. У наш проект включені і Junit, і TestNG, і я продовжував отримувати assertThrows повертає недійсну помилку, поки не змінив її на assertExpects. Виявилося, що я використовую org.testng.Assert.
barryku

-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.