Утверждения в JUnit 4 и JUnit 5

Утверждения в JUnit 4 и JUnit 5

1. Вступление

В этой статье мы собираемся подробно изучить утверждения, доступные в JUnit.

После статей оmigrating from JUnit 4 to JUnit 5 иA Guide to JUnit 5 мы подробно рассмотрим различные утверждения, доступные в JUnit 4 и JUnit 5.

Мы также выделим улучшения, внесенные в утверждения в JUnit 5.

2. Утверждения

Assertions are utility methods to support asserting conditions in tests; эти методы доступны через классAssert в JUnit 4 иAssertions в JUnit 5.

Чтобы повысить удобочитаемость теста и самих утверждений, всегда рекомендуется статическиimport соответствующий класс. Таким образом, мы можем напрямую ссылаться на сам метод утверждения без представления класса в качестве префикса.

Давайте начнем изучать утверждения, доступные в JUnit 4.

3. Утверждения в JUnit 4

В этой версии библиотеки утверждения доступны для всех типов примитивов,Objects, иarrays (либо примитивов, либоObjects).

Порядок параметров в утверждении - это ожидаемое значение, за которым следует фактическое значение; необязательно первым параметром может быть сообщениеString, которое представляет собой вывод сообщения оцениваемого условия.

Есть только одно несколько иное определение утвержденийassertThat, но мы рассмотрим его позже.

Начнем сassertEquals.

3.1. assertEqualsс

УтверждениеassertEquals проверяет, что ожидаемые и фактические значения равны:

@Test
public void whenAssertingEquality_thenEqual() {
    String expected = "example";
    String actual = "example";

    assertEquals(expected, actual);
}

Также можно указать сообщение, которое будет отображаться в случае сбоя утверждения:

assertEquals("failure - strings are not equal", expected, actual);

3.2. assertArrayEqualsс

Если мы хотим утверждать, что два массива равны, мы можем использоватьassertArrayEquals:

@Test
public void whenAssertingArraysEquality_thenEqual() {
    char[] expected = {'J','u','n','i','t'};
    char[] actual = "Junit".toCharArray();

    assertArrayEquals(expected, actual);
}

Если оба массиваnull, утверждение будет считать их равными:

@Test
public void givenNullArrays_whenAssertingArraysEquality_thenEqual() {
    int[] expected = null;
    int[] actual = null;

    assertArrayEquals(expected, actual);
}

3.3. assertNotNull иassertNull

Когда мы хотим проверить, является ли объектnull, мы можем использовать утверждениеassertNull:

@Test
public void whenAssertingNull_thenTrue() {
    Object car = null;

    assertNull("The car should be null", car);
}

Напротив, если мы хотим утверждать, что объект не должен быть нулевым, мы можем использоватьassertNotNull assertion.

3.4. assertNotSame иassertSame

С помощьюassertNotSame можно проверить, не относятся ли две переменные к одному и тому же объекту:

@Test
public void whenAssertingNotSameObject_thenDifferent() {
    Object cat = new Object();
    Object dog = new Object();

    assertNotSame(cat, dog);
}

В противном случае, когда мы хотим убедиться, что две переменные относятся к одному и тому же объекту, мы можем использовать утверждениеassertSame.

3.5. assertTrue иassertFalse

В случае, если мы хотим убедиться, что определенным условием являетсяtrue илиfalse, мы можем соответственно использовать утверждениеassertTrue или утверждениеassertFalse:

@Test
public void whenAssertingConditions_thenVerified() {
    assertTrue("5 is greater then 4", 5 > 4);
    assertFalse("5 is not greater then 6", 5 > 6);
}

3.6. fail

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

Давайте посмотрим, как мы можем использовать его в первом сценарии:

@Test
public void whenCheckingExceptionMessage_thenEqual() {
    try {
        methodThatShouldThrowException();
        fail("Exception not thrown");
    } catch (UnsupportedOperationException e) {
        assertEquals("Operation Not Supported", e.getMessage());
    }
}

3.7. assertThatс

УтверждениеassertThat - единственное в JUnit 4, которое имеет обратный порядок параметров по сравнению с другими утверждениями.

В этом случае утверждение содержит необязательное сообщение об ошибке, фактическое значение и объектMatcher.

Давайте посмотрим, как мы можем использовать это утверждение, чтобы проверить, содержит ли массив определенные значения:

@Test
public void testAssertThatHasItems() {
    assertThat(
      Arrays.asList("Java", "Kotlin", "Scala"),
      hasItems("Java", "Kotlin"));
}

Дополнительная информация о мощном использовании утвержденияassertThat с объектомMatcher доступна вTesting with Hamcrest.

4. Утверждения JUnit 5

JUnit 5 сохранил многие из методов утверждения JUnit 4, добавив при этом несколько новых, использующих поддержку Java 8.

Также в этой версии библиотеки утверждения доступны для всех типов примитивов,Objects, и массивов (либо примитивов, либо объектов).

Порядок параметров утверждений изменился, перенеся параметр выходного сообщения в качестве последнего параметра. Благодаря поддержке Java 8, выходное сообщение может бытьSupplier, что позволяет выполнять его ленивую оценку.

Давайте приступим к рассмотрению утверждений, доступных также в JUnit 4.

4.1. assertArrayEqualsс

УтверждениеassertArrayEquals проверяет, что ожидаемый и фактический массивы равны:

@Test
public void whenAssertingArraysEquality_thenEqual() {
    char[] expected = { 'J', 'u', 'p', 'i', 't', 'e', 'r' };
    char[] actual = "Jupiter".toCharArray();

    assertArrayEquals(expected, actual, "Arrays should be equal");
}

Если массивы не равны, в качестве вывода будет отображаться сообщение «Arrays should be equal».

4.2. assertEqualsс

В случае, если мы хотим утверждать, что дваfloats равны, мы можем использовать простое утверждениеassertEquals:

@Test
public void whenAssertingEquality_thenEqual() {
    float square = 2 * 2;
    float rectangle = 2 * 2;

    assertEquals(square, rectangle);
}

Однако, если мы хотим утверждать, что фактическое значение отличается на предопределенную дельту от ожидаемого значения, мы все равно можем использоватьassertEquals, но мы должны передать значение дельты в качестве третьего параметра:

@Test
public void whenAssertingEqualityWithDelta_thenEqual() {
    float square = 2 * 2;
    float rectangle = 3 * 2;
    float delta = 2;

    assertEquals(square, rectangle, delta);
}

4.3. assertTrue иassertFalse

С утверждениемassertTrue можно проверить, что предоставленные условия -true:

@Test
public void whenAssertingConditions_thenVerified() {
    assertTrue(5 > 4, "5 is greater the 4");
    assertTrue(null == null, "null is equal to null");
}

Благодаря поддержке лямбда-выражения в утверждение можно указатьBooleanSupplier вместо условияboolean.

Давайте посмотрим, как мы можем утверждать правильностьBooleanSupplier, используя утверждениеassertFalse:

@Test
public void givenBooleanSupplier_whenAssertingCondition_thenVerified() {
    BooleanSupplier condition = () -> 5 > 6;

    assertFalse(condition, "5 is not greater then 6");
}

4.4. assertNull иassertNotNull

Когда мы хотим утверждать, что объект неnull, мы можем использовать утверждениеassertNotNull:

@Test
public void whenAssertingNotNull_thenTrue() {
    Object dog = new Object();

    assertNotNull(dog, () -> "The dog should not be null");
}

В противном случае мы можем использовать утверждениеassertNull, чтобы проверить, действительно ли этоnull:

@Test
public void whenAssertingNull_thenTrue() {
    Object cat = null;

    assertNull(cat, () -> "The cat should be null");
}

В обоих случаях сообщение об ошибке будет получено ленивым способом, поскольку этоSupplier.

4.5. assertSame иassertNotSame

Когда мы хотим утверждать, что ожидаемое и фактическое относятся к одному и тому жеObject, мы должны использовать утверждениеassertSame:

@Test
public void whenAssertingSameObject_thenSuccessfull() {
    String language = "Java";
    Optional optional = Optional.of(language);

    assertSame(language, optional.get());
}

В противном случае мы можем использоватьassertNotSame.

4.6. failс

Утверждениеfail не проходит тест с предоставленным сообщением об ошибке, а также с основной причиной. Это может быть полезно, чтобы отметить тест, когда он еще не завершен:

@Test
public void whenFailingATest_thenFailed() {
    // Test not completed
    fail("FAIL - test not completed");
}

4.7. assertAllс

Одно из новых утверждений, введенных в JUnit 5, -assertAll.

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

Давайте определим сгруппированное утверждение:

@Test
public void givenMultipleAssertion_whenAssertingAll_thenOK() {
    assertAll(
      "heading",
      () -> assertEquals(4, 2 * 2, "4 is 2 times 2"),
      () -> assertEquals("java", "JAVA".toLowerCase()),
      () -> assertEquals(null, null, "null is equal to null")
    );
}

Выполнение сгруппированного утверждения прерывается только тогда, когда один из исполняемых файлов выдает исключение из черного списка (например,OutOfMemoryError).

4.8. assertIterableEqualsс

assertIterableEquals утверждает, что ожидаемые и фактические итерации полностью равны.

Чтобы быть равными, обе итерации должны возвращать одинаковые элементы в одном и том же порядке, и не требуется, чтобы эти две итерации были одного типа, чтобы быть равными.

Учитывая это, давайте посмотрим, как мы можем утверждать, что два списка разных типов (например,LinkedList иArrayList) равны:

@Test
public void givenTwoLists_whenAssertingIterables_thenEquals() {
    Iterable al = new ArrayList<>(asList("Java", "Junit", "Test"));
    Iterable ll = new LinkedList<>(asList("Java", "Junit", "Test"));

    assertIterableEquals(al, ll);
}

АналогичноassertArrayEquals, если обе итерации равны нулю, они считаются равными.

4.9. assertLinesMatchс

assertLinesMatch утверждает, что ожидаемый списокString соответствует фактическому списку.

Этот метод отличается отassertEquals иassertIterableEquals тем, что для каждой пары ожидаемых и фактических строк он выполняет следующий алгоритм:

  1. проверьте, равна ли ожидаемая строка фактической. Если да, то это продолжается со следующей парой

  2. обрабатывает ожидаемую строку как регулярное выражение и выполняет проверку с помощью методаString.matches(). Если да, то это продолжается со следующей парой

  3. проверьте, является ли ожидаемая строка маркером перемотки вперед. Если да, примените ускоренную перемотку вперед и повторите алгоритм, начиная с шага 1

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

@Test
public void whenAssertingEqualityListOfStrings_thenEqual() {
    List expected = asList("Java", "\\d+", "JUnit");
    List actual = asList("Java", "11", "JUnit");

    assertLinesMatch(expected, actual);
}

4.10. assertNotEqualsс

В дополнение кassertEquals утверждениеassertNotEquals утверждает, что ожидаемые и фактические значения не равны:

@Test
public void whenAssertingEquality_thenNotEqual() {
    Integer value = 5; // result of an algorithm

    assertNotEquals(0, value, "The result cannot be 0");
}

Если обаnull, утверждение не выполняется.

4.11. assertThrowsс

Чтобы повысить простоту и удобочитаемость, новое утверждениеassertThrows позволяет нам ясный и простой способ утверждать, генерирует ли исполняемый файл исключение указанного типа.

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

@Test
void whenAssertingException_thenThrown() {
    Throwable exception = assertThrows(
      IllegalArgumentException.class,
      () -> {
          throw new IllegalArgumentException("Exception message");
      }
    );
    assertEquals("Exception message", exception.getMessage());
}

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

4.12. assertTimeout и assertTimeoutPreemptively

В случае, если мы хотим утверждать, что выполнение предоставленногоExecutable заканчивается раньше заданногоTimeout, мы можем использовать утверждениеassertTimeout:

@Test
public void whenAssertingTimeout_thenNotExceeded() {
    assertTimeout(
      ofSeconds(2),
      () -> {
        // code that requires less then 2 minutes to execute
        Thread.sleep(1000);
      }
    );
}

Однако с утверждениемassertTimeout предоставленный исполняемый файл будет выполняться в том же потоке, что и вызывающий код. Следовательно, выполнение поставщика не будет преждевременно прервано, если истечет время ожидания.

В случае, если мы хотим быть уверены, что выполнение исполняемого файла будет прервано по истечении времени ожидания, мы можем использовать утверждениеassertTimeoutPreemptively.

Оба утверждения могут принимать вместоExecutable,ThrowingSupplier, представляющий любой общий блок кода, который возвращает объект и который потенциально может вызватьThrowable.

5. Заключение

В этом руководстве мы рассмотрели все утверждения, доступные в JUnit 4 и JUnit 5.

Мы кратко осветили улучшения, внесенные в JUnit 5, с введением новых утверждений и поддержкой лямбд.

Как всегда, доступен полный исходный код этой статьиover on GitHub.