Это продолжение туториала по JUnit 5. Введение опубликовано здесь.

Оглавление

  1. Настройка

  2. Аннотация @ParameterizedTest

  3. Источники тестовых аргументов

  4. Параметризованные тесты с несколькими аргументами.

  5. Вывод

1. Настройка

Включите зависимость junit-jupiter-params, чтобы использовать параметризованные тесты.

Последнюю версию можно найти по этой ссылке.

pom.xml

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-params</artifactId>
    <version>${junit-version}</version>
    <scope>test</scope>
</dependency>

2. Аннотация @ParameterizedTest

  • Используйте аннотацию @ParameterizedTest, чтобы выполнить тест несколько раз, но с разными аргументами. Нам не нужно использовать аннотацию @Test, вместо этого в таких тестах используется только аннотация @ParameterizedTest.

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

  • В данном примере testPalindrome будет вызываться 2 раза для каждой строки, указанной в аннотации @ValueSource. Мы получаем доступ к аргументу, используя параметр word метода.

  • Используйте аргумент name в аннотации @ParameterizedTest, чтобы настроить отображаемое сообщение.

public class ParameterizedTests 
{
    public boolean isPalindrome(String s) {
        return s == null ? false : StringUtils.reverse(s).equals(s);
    }
    
    @ParameterizedTest(name = "{index} - {0} is a palindrome")
    @ValueSource(strings = { "12321", "pop" })
    void testPalindrome(String word) {
        assertTrue(isPalindrome(word));
    }
}

3. Источники тестовых аргументов

Есть несколько способов передать аргументы методу тестирования. Давайте изучим их.

3.1. Аннотация @ValueSource

  • Используйте @ValueSource для простых буквальных значений, таких как примитивы и строки.

  • Она определяет один массив значений и может использоваться только для предоставления одного аргумента для каждого параметризованного вызова теста.

  • Java поддерживает автобоксирование, поэтому мы также можем использовать литералы в их классах-оболочках.

  • Мы не можем передавать null в качестве аргумента даже для типов String и Class.

@ParameterizedTest
@ValueSource(ints = { 1, 2, 3 })
void testMethod(int argument) {
    //test code
}

@ParameterizedTest
@ValueSource(ints = { 1, 2, 3 })
void testMethodWithAutoboxing(Integer argument) {
    //test code
}

3.2. Аннотация @NullSource

Она предоставляет единственный null аргумент методу, аннотированному @ParameterizedTest.

@ParameterizedTest
@NullSource
void testMethodNullSource(Integer argument) {
    assertTrue(argument == null);
}

3.3. Аннотация @EmptySource

Она предоставляет метод, аннотированный @ParameterizedTest, с единственным пустым аргументом следующих типов:

  • java.lang.String

  • java.util.List

  • java.util.Set

  • java.util.Map

  • примитивные массивы (например, int [])

  • массивы объектов (например, String [])

@ParameterizedTest
@EmptySource
void testMethodEmptySource(String argument) {
    assertTrue(StringUtils.isEmpty(argument));
}

3.4. Аннотация @NullAndEmptySource

Она сочетает в себе функциональность @NullSource и @EmptySource. В данном примере тестовый метод будет вызываться два раза - сначала со значением null, а затем со значением empty.

@ParameterizedTest
@NullAndEmptySource
void testMethodNullAndEmptySource(String argument) {
    assertTrue(StringUtils.isEmpty(argument));
}

Проверка null и non-null значений в одном тесте

Мы уже знаем, что аннотация @ValueSource не поддерживает значение null.

Таким образом, используя @NullSource и @EmptySource в аннотации @ValueSource, мы можем тестировать nullnon-null и пустые значения в одном и том же тесте.

3.5. Аннотация @EnumSource

Это удобный способ использования Enum констант. Метод тестирования будет вызываться для каждой константы перечисления за раз.

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

enum Direction {
    EAST, WEST, NORTH, SOUTH
}

@ParameterizedTest
@EnumSource(Direction.class)
void testWithEnumSource(Direction d) {
    assertNotNull(d);
}

3.6. Аннотация @MethodSource

  • Она используется для ссылки на один или несколько фабричных методов тестового класса или внешних классов. Фабричный метод должен генерировать поток аргументов, где каждый аргумент в потоке будет использоваться методом, аннотированным @ParameterizedTest.

  • Фабричный метод должен быть static, если тестовый класс не аннотирован с помощью @TestInstance(Lifecycle.PER_CLASS).

  • Кроме того, фабричный метод не должен принимать аргументы.

@ParameterizedTest
@MethodSource("argsProviderFactory")
void testWithMethodSource(String argument) {
    assertNotNull(argument);
}

static Stream<String> argsProviderFactory() {
    return Stream.of("alex", "brian");
}

Если мы явно не предоставим имя фабричного метода через @MethodSource, JUnit будет искать фабричный метод, имя которого по умолчанию совпадает с именем текущего метода с аннотацией @ParameterizedTest.

Поэтому, в примере, если мы не предоставим имя метода argsProviderFactory в аннотации @MethodSource, Junit будет искать имя метода testWithMethodSource с возвращаемым типом Stream<String>.

@ParameterizedTest
@MethodSource
void testWithMethodSource(String argument) {
    assertNotNull(argument);
}

static Stream<String> testWithMethodSource() {
    return Stream.of("alex", "brian");
}

Также поддерживаются потоки для примитивных типов (DoubleStream, IntStream и LongStream).

@ParameterizedTest
@MethodSource("argsProviderFactory")
void testWithMethodSource(int argument) {
    assertNotEquals(9, argument);
}

static IntStream argsProviderFactory() {
    return IntStream.range(0, 10);
}

3.7. Аннотация @CsvSource

Эта аннотация позволяет нам задавать списки аргументов как значения, разделенные запятыми. Каждый CSV токен представляет собой строку CSV и приводит к одному вызову параметризованного теста.

Задайте для свойства ignoreLeadingAndTrailingWhitespace значение true или false, указывающее на то, что Junit должен принимать или игнорировать пробелы в CSV токенах.

@ParameterizedTest
@CsvSource(value = {
    "alex, 30",
    "brian, 35",
    "charles, 40"
}, ignoreLeadingAndTrailingWhitespace = true)
void testWithCsvSource(String name, int age) {
    assertNotNull(name);
    assertTrue(age > 0);
}

3.8. Аннотация @CsvFileSource

Эта аннотация очень похожа на @CsvSource за исключением того, что мы читаем токены CSV из файла вместо чтения токенов в исходном тексте. CSV файл можно прочитать по classpath или из локальной файловой системы.

Разделителем по умолчанию является запятая (,), но мы можем использовать другой символ, установив атрибут разделителя.

Обратите внимание, что любая строка, начинающаяся с символа #, будет интерпретироваться как комментарий и игнорироваться.

@ParameterizedTest
@CsvFileSource(resources = "employeeData.csv", numLinesToSkip = 0)
void testWithCsvFileSource(String name, int age) {
    assertNotNull(name);
    assertTrue(age > 0);
}

3.9. Аннотация @ArgumentsSource

Аннотацию @ArgumentsSource можно использовать для указания настраиваемого многоразового поставщика аргументов ArgumentsProvider.

@ParameterizedTest(name = "{index} - {0} is older than 40")
@ArgumentsSource(EmployeesArgumentsProvider.class)
void isEmployeeAgeGreaterThan40(Employee e) {
    assertTrue(Period.between(e.getDob(), LocalDate.now()).get(ChronoUnit.YEARS) > 40);
}

class EmployeesArgumentsProvider implements ArgumentsProvider {
    @Override
    public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
        return Stream.of(
          Arguments.of(new Employee(1, "Alex", LocalDate.of(1980, 2, 3))),
          Arguments.of(new Employee(2, "Brian", LocalDate.of(1979, 2, 3))),
          Arguments.of(new Employee(3, "Charles", LocalDate.of(1978, 2, 3)))
        );
    }
}

4. Параметризованные тесты с несколькими аргументами.

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

4.1. Аннотация @CsvSource

Как показано в предыдущем разделе 3.7, с помощью аннотации @CsvSource мы можем предоставить множество литералов и простых типов аргументов.

Нам нужно предоставить все аргументы в одном токене CSV, а затем определить соответствующие аргументы метода.

@ParameterizedTest
@CsvSource({
    "alex, 30, HR, Active",
    "brian, 35, Technology, Active",
    "charles, 40, Finance, Purged"
})
void testWithCsvSource(String name, int age, String department, String status) {
    //test code
}

4.2. Интерфейс ArgumentsProvider

Чтобы предоставить несколько тестовых аргументов сложных или настраиваемых типов, мы должны использовать аннотацию @ArgumentsSource с аннотацией ArgumentsProvider.

В примере мы передаем три аргумента метода тестирования testArgumentsSource, типов EmployeeLocalDateи enum константы типа Direction.

@ParameterizedTest
@ArgumentsSource(EmployeesArgumentsProvider.class)
void testArgumentsSource(Employee e, LocalDate date, Direction d) {
    assertTrue(Period.between(e.getDob(), LocalDate.now()).get(ChronoUnit.YEARS) > 40);
    assertNotNull(date);
    assertNotNull(d);
}

class EmployeesArgumentsProvider implements ArgumentsProvider {
    @Override
    public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
        return Stream.of(
          Arguments.of(new Employee(1, "Alex", 
                  LocalDate.of(1980, 2, 3)), LocalDate.now(), Direction.EAST),
          Arguments.of(new Employee(2, "Brian", 
                  LocalDate.of(1979, 2, 3)), LocalDate.now(), Direction.NORTH),
          Arguments.of(new Employee(3, "Charles", 
                  LocalDate.of(1978, 2, 3)), LocalDate.now(), Direction.SOUTH)
        );
    }

5. Вывод

Junit 5 аннотация @ParameterizedTest очень полезна при написании тестов, которые необходимо вызывать для тестирования несколько раз, но с разными аргументами. Junit предоставляет несколько способов, которые можно использовать декларативно для предоставления аргументов методу тестирования.

Мы также можем комбинировать разные аннотации для тестирования различных типов входных данных в одном тесте.

Есть некоторые более сложные понятия, такие как агрегатор аргументов, конвертер аргументов и т.д. Пожалуйста, прочитайте официальную документацию Junit для получения последней информации.

Хорошего изучения!!!

Скачать исходный код

Комментарии (0)