Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Параметризованные тесты

Часто одну проверку нужно повторить для многих входных данных: слаг для десяти разных заголовков, отказ для пустого, пробельного и null-заголовка. Копировать тест десять раз — плохая идея. Параметризованный тест пишется один раз, получает данные через параметры метода, и JUnit запускает его по разу для каждого набора значений.

Тестируемый класс

Слаг (slug) — часть адреса поста, построенная из заголовка: Hello, World! превращается в hello-world. Создайте src/main/java/com/example/blog/Slugs.java:

// src/main/java/com/example/blog/Slugs.java
package com.example.blog;
 
import java.util.Locale;
 
public final class Slugs {
 
    private Slugs() {
    }
 
    public static String of(String title) {
        return title.toLowerCase(Locale.ROOT)
                .replaceAll("[^a-z0-9]+", "-")
                .replaceAll("^-|-$", "");
    }
}

Всё, кроме латинских букв и цифр, превращается в дефис; дефисы по краям удаляются. Кириллицу этот простой вариант не поддерживает, поэтому в примерах заголовки латиницей.

@ValueSource

Вместо @Test пишут @ParameterizedTest и добавляют источник данных. Самый простой — @ValueSource, массив значений одного типа:

// src/test/java/com/example/blog/SlugsTest.java
@ParameterizedTest
@ValueSource(strings = {"Hello", "Hello, World!", "  Java 25  "})
void slugHasNoSpaces(String title) {
    assertFalse(Slugs.of(title).contains(" "));
}

Тест выполнится три раза, каждый раз с другим title. Кроме strings есть ints, longs, doubles и другие массивы. Аннотации импортируются из org.junit.jupiter.params и org.junit.jupiter.params.provider — зависимость junit-jupiter их уже содержит.

@CsvSource

Когда тесту нужно несколько параметров — вход и ожидаемый результат, — используйте @CsvSource. Каждая строка — один запуск, значения разделены запятыми:

// src/test/java/com/example/blog/SlugsTest.java
@ParameterizedTest
@CsvSource({
        "Hello,           hello",
        "'Hello, World!', hello-world",
        "'  Java 25  ',   java-25",
        "JUnit & Mockito, junit-mockito"
})
void slugFromTitle(String title, String expected) {
    assertEquals(expected, Slugs.of(title));
}

Пробелы вокруг значений обрезаются, поэтому столбцы можно выравнивать. Значение с запятой или со значимыми пробелами берут в одинарные кавычки. JUnit сам преобразует строки в типы параметров: int, long, boolean, BigDecimal, перечисления.

Пустые значения и null

@NullAndEmptySource добавляет два запуска: с null и с пустой строкой. Вместе с @ValueSource получаются сразу все случаи «ничего»:

// src/test/java/com/example/blog/SlugsTest.java
@ParameterizedTest
@NullAndEmptySource
@ValueSource(strings = {" ", "\t"})
void blankTitleIsRejected(String title) {
    PostService service = new PostService(new InMemoryPostRepository(), (to, message) -> { });
 
    assertThrows(IllegalArgumentException.class, () -> service.create(title, "anna"));
}

Четыре запуска: null, "", пробел и табуляция. Три теста класса вместе дают в отчёте Maven Tests run: 11.

Имена запусков

IDE показывает каждый запуск отдельно. JUnit 6 берёт строковые значения в кавычки, чтобы пустые и пробельные строки были видны: запуски blankTitleIsRejected называются [1] null, [2] "", [3] " " и [4] "\t". Свой формат задаёт параметр name:

// src/test/java/com/example/blog/SlugsTest.java
@ParameterizedTest(name = "слаг для {0} — {1}")

{0}, {1} — параметры, {index} — номер запуска. Теперь запуски называются слаг для "Hello" — "hello" и так далее. В отчётах Maven запуски называются по методу и номеру: slugFromTitle(String, String)[2].

Частая ошибка

Если забыть кавычки вокруг значения с запятой, строка разобьётся на три столбца. JUnit 6 не жалуется на лишний столбец, а просто берёт первые два:

"Hello, World!, hello-world"
[ERROR] com.example.blog.CsvFailTest.slugFromTitle(String, String)[2] -- Time elapsed: 0.015 s <<< FAILURE!
org.opentest4j.AssertionFailedError: expected: <World!> but was: <hello>

Заголовком стало Hello, а ожидаемым значением — World!. Значения с запятыми всегда берите в одинарные кавычки: 'Hello, World!'.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.