Параметризованные автотесты — это удобный инструмент, который помогает тестировать программное обеспечение быстрее и эффективнее. Вместо написания множества однотипных тестов с разными входными данными, можно использовать один тестовый метод, подставляя в него разные параметры. Это упрощает код и делает его более удобным в поддержке. JUnit 5, популярный фреймворк для тестирования Java-приложений, предлагает множество возможностей для работы с параметризованными тестами, делая процесс тестирования гибче и удобнее.
Что такое параметризованные автотесты
Параметризованные тесты позволяют запускать один и тот же тестовый метод с разными входными значениями. В классическом подходе для каждого сценария создается отдельный тест, что ведет к дублированию кода. С параметризованными тестами достаточно один раз определить логику, а затем подставлять разные данные. Это делает тесты более читаемыми и удобными в поддержке.
JUnit 5 значительно улучшил работу с параметризованными тестами по сравнению с JUnit 4. Ранее приходилось параметризовать весь тестовый класс, что было не всегда удобно. Теперь можно параметризовать отдельные методы, комбинируя их с обычными тестами. Также расширился список источников данных: дополнительно можно использовать CSV-файлы, методы с потоками данных и другие варианты.
Зачем нужны параметризованные тесты
Вот основные преимущества параметризованных тестов:
Меньше дублирования кода. Один метод тестирует сразу несколько сценариев. Соответственно, это уменьшает объем кода и снижает вероятность ошибок, связанных с дублированием.
Легче покрывать разные случаи, например пограничные условия и особые случаи. Можно быстро провести новый тест, просто добавив данные.
Экономия времени. Создание и поддержка тестов занимает меньше времени.
Удобочитаемость. Четкое разделение логики теста и тестовых данных. Более того, в CSV-файлах, данные доступны для анализа и редактирования даже для тех членов команды, которые не являются разработчиками.
Гибкость. Можно тестировать разные входные данные без изменения самого теста.
Системность. Метод стимулирует мыслить в терминах наборов данных и сценариев, а не отдельных вызовов методов, что способствует более полному охвату возможных ситуаций.
Как настроить JUnit 5 для параметризованных тестов
Чтобы использовать параметризованные тесты в JUnit 5, сначала добавьте в проект соответствующую зависимость. Актуальная версия зависимости доступна по ссылке https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter
Для Maven:
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>*Последняя версия*</version>
<scope>test</scope>
</dependency>
Для Gradle:
testImplementation 'org.junit.jupiter:junit-jupiter:*Последняя версия*'
Основная аннотация для параметризованных тестов — @ParameterizedTest. Она заменяет стандартную @Test и указывает, что метод может запускаться несколько раз с различными наборами параметров.
Источники данных для параметризованных тестов
JUnit 5 поддерживает несколько способов передачи массивов данных в тесты.
@ValueSource — простые значения
Если нужно передать массив простых значений (числа, логические значения, строки), используйте @ValueSource:
@ParameterizedTest
@ValueSource(strings = {"apple", "banana", "orange"})
void testFruitNames(String fruit) {
assertNotNull(fruit);
assertTrue(fruit.length() > 0);
}
Этот тест запустится три раза: для каждого значения из массива.
@EnumSource — для перечислений
Если тест использует значения перечислений, поможет @EnumSource:
enum DayOfWeek {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY
}
@ParameterizedTest
@EnumSource(DayOfWeek.class)
void testDaysOfWeek(DayOfWeek day) {
assertNotNull(day);
}
Тест выполнится для всех значений DayOfWeek.
@MethodSource — передача данных из метода
Если проще создавать сложные наборы тестовых данных программным путем, то стоит воспользоваться @MethodSource:
@ParameterizedTest
@MethodSource("provideTestData")
void testWithMethodSource(String input, int expected) {
assertEquals(expected, input.length());
}
static Stream<Arguments> provideTestData() {
return Stream.of(
Arguments.of("apple", 5),
Arguments.of("banana", 6),
Arguments.of("orange", 6)
);
}
Тест выполнится три раза, получая данные, в данном случае, из метода provideTestData.
Использование CSV-файлов для параметризации тестов
Если у вас много тестовых данных, удобнее хранить их в CSV-файле. JUnit 5 поддерживает это с помощью @CsvFileSource.
Пример CSV-файла (test-data.csv):
input,expected
apple,5
banana,6
orange,6
Использование в тесте:
@ParameterizedTest
@CsvFileSource(resources = "/test-data.csv", numLinesToSkip = 1)
void testWithCsvFileSource(String input, int expected) {
assertEquals(expected, input.length());
}
Здесь тест будет загружать данные из test-data.csv, расположенного в корне ресурсов проекта (папка resources), и запускаться три раза.
Имена переменных в методе (input, expected) не обязательно должны совпадать с именами столбцов в CSV-файле (их может не быть вовсе, тогда нет необходимости указывать значение numLinesToSkip). JUnit сопоставляет значения по порядку: первый столбец с первым параметром, второй столбец — со вторым, и так далее.
Комментарии в CSV
Вариант 1. Строки, начинающиеся с #, будут пропущены:
input,expected
apple,5
# banana,6 (этот тест временно отключен)
orange,6
Вариант 2. Параметр numLinesToSkip — позволяет пропустить заданное количество строк в начале файла. Это полезно, когда CSV-файл содержит заголовки столбцов или какие-либо вводные данные, которые не должны обрабатываться как тестовые случаи.
Например:
@ParameterizedTest
@CsvFileSource(resources = "/test-data.csv", numLinesToSkip = 2)
void testWithSkippedLines(String input, int expected) {
assertEquals(expected, input.length());
}
В этом примере будут пропущены первые две строки CSV-файла.
Настройка разделителей
По умолчанию используется запятая, но можно задать другой разделитель. Для этого предусмотрены параметры delimiter и delimiterString (для многосимвольных разделителей):
@ParameterizedTest
@CsvFileSource(
resources = "/data-with-custom-delimiter.csv",
numLinesToSkip = 1,
delimiter = ';',
delimiterString = "||"
)
void testWithCustomDelimiter(String input, String expected) {
assertEquals(expected, input.length());
}
Использование нескольких файлов
Можно загружать данные сразу из нескольких файлов:
@ParameterizedTest
@CsvFileSource(
resources = {"/data-set-1.csv", "/data-set-2.csv"},
numLinesToSkip = 1
)
void testWithMultipleFiles(String input, String expected) {
assertEquals(expected, input.length());
}
Пропуск первых строк при этом, регулируемый параметром numLinesToSkip, применяется к каждому файлу.
Работа с кодировками
Для работы с файлами в различных кодировках и с разными разделителями строк предусмотрены параметры encoding и lineSeparator:
@ParameterizedTest
@CsvFileSource(
resources = "/data-in-windows-encoding.csv",
numLinesToSkip = 1,
encoding = "Cp1251",
lineSeparator = "\r\n"
)
void testWithCustomEncodingAndLineSeparator(String input, String expected) {
assertEquals(expected, input.length());
}
Оформление тестов для отчетности
При генерации отчетов (например, в Allure Reports) для параметризованных тестов лучше использовать свой специфичный параметр name, который поддерживает различные способы использования тестовых данных: {index} для указания индекса текущей итерации, {arguments} — всех аргументов тестового метода, и {0}, {1}, ... — для использования конкретных аргументов по их индексам.
Заключение
Параметризованные тесты в JUnit 5 помогают упростить и ускорить тестирование. Они сокращают дублирование кода, упрощают поддержку тестов и делают процесс тестирования гибким. Возможность загружать тестовые данные из CSV-файлов позволяет четко разделять логику тестов и входные данные.
Если использовать параметризованные тесты правильно, это поможет сделать ваш код более надежным, а процесс тестирования — более прозрачным и удобным.