Использование метода assertAll против утверждения в отдельных операторах

Метод assertAll используется для проверки всех переданных ему утверждений.

Вот что о методе говорится в официальной документации:

Утверждает, что все предоставленные executables не вызывают исключений.

Если какой-либо предоставленный Executable выдает исключение (т. е. Throwable или любой его подкласс), все оставшиеся executables все равно будут выполняться, а все исключения будут агрегированы и зарегистрированы в MultipleFailuresError. Однако, если executable генерирует исключение из черного списка — например, OutOfMemoryError — выполнение немедленно останавливается, а исключение из черного списка создается как есть, но замаскировано как непроверенное исключение.

Предоставленный heading будет включен в строку сообщения для MultipleFailuresError.

Применение

@Test
void testAssertions() {
    assertAll(
        () -> assertEquals("1", "1"),
        () -> assertTrue(1 == 2),
        ......
    );
}

Использование assertAll против утверждения отдельно

Разница между передачей утверждений этому методу и утверждением их в отдельных утверждениях заключается в том, что «метод assertAllвыполняет все переданные ему утверждения, даже если какое-то утверждение не выполняется».

// Example of assertAll
@Test
void testAssertions() {
    assertAll(
        () -> assertEquals("1", "1"),
        () -> assertEquals("1", "2"),
        () -> assertTrue(1 == 2)
    );
}


/*
Output:

org.opentest4j.MultipleFailuresError: Multiple Failures (2 failures)
  org.opentest4j.AssertionFailedError: expected: <1> but was: <2>
  org.opentest4j.AssertionFailedError: expected: <true> but was: <false>
*/

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

// Example of asserting separately
@Test
void testAssertions() {
    assertEquals("1", "1");

    /*
    when the test fails here it throws an AssertionFailedError 
    and the test fails.
    The below assertTrue will not be executed
    */
    assertEquals("1", "2");
    assertTrue(1 == 2);
}

/*
Output: 
org.opentest4j.AssertionFailedError: 
Expected :1
Actual :2
*/

Таким образом, выполнение всех утверждений даже в случае сбоя утверждения является преимуществом метода assertAll.

Работающий

Давайте проверим код метода assertAll, чтобы увидеть, как он работает.

// code from JUnit 5

static void assertAll(String heading, Stream<Executable> executables) {
    Preconditions.notNull(executables, "executables stream must not be null");
  
    List<Throwable> failures = executables //
      .peek(executable -> Preconditions.notNull(executable, "individual executables must not be null"))//
      .map(executable -> {
       try {
        executable.execute();
        return null;
       }
       catch (Throwable t) {
        BlacklistedExceptions.rethrowIfBlacklisted(t);
        return t;
       }
      }) //
      .filter(Objects::nonNull) //
      .collect(Collectors.toList());
  
    if (!failures.isEmpty()) {
     MultipleFailuresError multipleFailuresError = new MultipleFailuresError(heading, failures);
     failures.forEach(multipleFailuresError::addSuppressed);
     throw multipleFailuresError;
    }
 }

Каждый объект/утверждение Executable выполняется в рамках try-catch, чтобы убедиться, что ошибка утверждения не вызывается сразу. Функция сопоставления/преобразования возвращает значение null, если тест проходит успешно,ивозвращает значение throwable, если тест не пройден.

Поток Executable’s преобразуется в поток Throwable’s. Ненулевые объекты фильтруются (неудачные утверждения) и собираются в список. Список оборачивается в MultipleFailuresError и выбрасывается в конце коллективно.

Это все на данный момент. Не стесняйтесь задавать любые вопросы или делиться любыми комментариями, которые у вас есть по поводу статьи. Увидимся в следующей статье.

Удачного кодирования!