assertAll против нескольких утверждений в JUnit5

Есть ли причина сгруппировать несколько утверждений:

public void shouldTellIfPrime(){
    Assertions.assertAll(
            () -> assertTrue(isPrime(2)),
            () -> assertFalse(isPrime(4))
    );
}

вместо этого:

public void shouldTellIfPrime(){
    Assertions.assertTrue(isPrime(2));
    Assertions.assertFalse(isPrime(4));
}

person Wilhelm Olejnik    schedule 25.11.2016    source источник


Ответы (2)


В assertAll интересно то, что он всегда проверяет все переданные ему утверждения, независимо от того, сколько из них завершилось ошибкой. Если все прошло, все в порядке - если хотя бы один не прошел, вы получите подробный результат всего, что пошло не так (и правильно в этом отношении).

Его лучше всего использовать для утверждения набора свойств, которые концептуально связаны друг с другом. Что-то, где ваш первый инстинкт был бы: «Я хочу утверждать это как единое целое».

Пример

Ваш конкретный пример не является оптимальным вариантом использования для assertAll, потому что проверка isPrime с простым и непростым числом не зависит друг от друга - настолько, что я бы рекомендовал написать для этого два метода тестирования.

Но предположим, что у вас есть простой класс, например адрес с полями city, street, number, и вы хотите утверждать, что это то, что вы ожидаете от них:

Address address = unitUnderTest.methodUnderTest();
assertEquals("Redwood Shores", address.getCity());
assertEquals("Oracle Parkway", address.getStreet());
assertEquals("500", address.getNumber());

Теперь, как только первое утверждение не сработает, вы никогда не увидите результатов второго, что может сильно раздражать. Есть много способов обойти это, и assertAll JUnit Jupiter является одним из них:

Address address = unitUnderTest.methodUnderTest();
assertAll("Should return address of Oracle's headquarter",
    () -> assertEquals("Redwood Shores", address.getCity()),
    () -> assertEquals("Oracle Parkway", address.getStreet()),
    () -> assertEquals("500", address.getNumber())
);

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

org.opentest4j.MultipleFailuresError:
    Should return address of Oracle's headquarter (3 failures)
    expected: <Redwood Shores> but was: <Walldorf>
    expected: <Oracle Parkway> but was: <Dietmar-Hopp-Allee>
    expected: <500> but was: <16>
person Nicolai Parlog    schedule 25.11.2016
comment
Но не стоит злоупотреблять этим! Единственный метод тестирования всегда должен проверять только одно предположение о производственном коде. Это основная причина, по которой у вас обычно есть только одно утверждение для каждого метода тестирования. - person Timothy Truckle; 25.11.2016
comment
Я согласен не злоупотреблять им и проверять только одно предположение, но не согласен с тем, что подсчет утверждений имеет какое-то значение. Это чисто синтаксическое соображение, не имеющее отношения к делу. Возьмем мой пример: скорее всего, Address:equals проверяет именно эти свойства, и в этом случае я мог бы проверить их с помощью одного утверждения. Логически никакой разницы не было бы, но внезапно это только одно утверждение. То же самое верно, если я приложу все усилия, чтобы создать сопоставитель Hamcrest для класса. - person Nicolai Parlog; 26.11.2016
comment
но не согласен с тем, что подсчет утверждений имеет какое-то значение. Я не предлагал считать утверждения. одно утверждение для каждого метода тестирования - это эмпирическое правило, не более, но не меньше ... В любом случае, если у вас есть несколько утверждений, следует спросить себя, действительно ли вы тестируете, проверяет ли одно предположение . - person Timothy Truckle; 26.11.2016
comment
Я не полностью согласен с одним тестом, одним практическим правилом утверждения. Предполагается, что тестируемый код выполняется быстро и просто. Поскольку ваши тесты масштабируются от низкоуровневых модульных тестов до высокоуровневых интеграционных тестов, это предположение не выполняется. Гораздо эффективнее запустить дорогостоящий фрагмент кода один раз и выполнить несколько недорогих утверждений по результатам, чем запускать дорогостоящий код несколько раз и каждый раз тестировать одну вещь. Утверждения в промежуточных точках также могут помочь при отладке. Пока вы четко обозначаете утверждения, нет проблем с использованием множественных. - person Fr Jeremy Krieg; 07.03.2019

Согласно документации здесь

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

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

Основное отличие состоит в том, что assertAll разрешит выполнение всех утверждений без нарушения потока, в то время как другие, такие как assertTrue, и лот остановит тест с ошибкой AssertionError

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

Есть ли причина группировать несколько утверждений

Если вы хотите, чтобы все утверждения выполнялись в модульном тесте.

person Nkosi    schedule 25.11.2016