JUnit Параметризованный тест с примером использования @Parameters
⚡ Умное резюме
Параметризованные тесты в JUnit Запустите один и тот же тестовый метод несколько раз с разными входными значениями, чтобы один метод охватывал множество сценариев. Аннотации @RunWith и @Parameters предоставляют набор данных для каждой итерации.
Что такое параметризованный тест в JUnit?
A параметризованный тест Это тест, который многократно выполняет один и тот же тестовый метод, используя разные значения. Он помогает разработчикам экономить время при написании тестов, которые отличаются только входными данными и ожидаемыми результатами.
Используя параметризованный тест, можно создать тестовый метод, который извлекает данные из некоторого источника данных. Это делает его простейшей формой тестирование на основе данных доступно внутри JUnit Самостоятельно, без необходимости использования каких-либо внешних библиотек.
Рассмотрим простой тест, который суммирует различные числа. Код может выглядеть так:
Описанный выше подход приводит к значительной избыточности. Для каждой новой пары чисел требуется еще одно утверждение внутри того же метода, и ошибка первого утверждения скрывает все последующие.
Необходим более простой подход. Используя параметризованный тест, вы можете добавить один метод, который предоставляет десять входных данных, и ваш тест будет автоматически запускаться десять раз.
Шаги по созданию параметризованного JUnit Тест
Приведённый ниже код демонстрирует пример параметризованного теста. Он проверяет метод sum() класса Airthematic, именно так он пишется во всём примере проекта.
Шаг 1) Создайте класс. В этом примере мы будем вводить два числа, используя метод sum(int, int), который вернет сумму заданных чисел.
Шаг 2) Создайте параметризованный тестовый класс.
Code объяснение
- Code Линия 11: Добавьте аннотацию `@RunWith(Parameterized.class)` к вашему тестовому классу.
- Code Линия 13: Объявление переменной firstNumber как частной и ее типа int.
- Code Линия 14: Объявляем переменную 'secondNumber' как приватную и указываем её тип как int.
- Code Линия 15: Объявление переменной 'expectedResult' как приватной и с типом int.
- Code Линия 16: Объявляем переменную 'airthematic' приватной и указываем тип как Airthematic.
@Бежать с(class_name.class): @Бежать с Аннотация используется для указания имени класса исполнителя. Если в качестве параметра не указан тип, среда выполнения выберет другой тип. ЗаблокироватьJUnit4КлассБегун по умолчанию.
Этот класс отвечает за запуск тестов с новым экземпляром теста. Он отвечает за вызов... JUnit Методы управления жизненным циклом, такие как настройка (связывание ресурсов) и завершение (освобождение ресурсов), описаны в [ссылка на соответствующий раздел]. JUnit испытательный стенд учебное пособие.
Для параметризации необходимо аннотировать класс с помощью @RunWith и передать требуемый .class для тестирования.
Шаг 3) Создайте конструктор, который будет хранить тестовые данные. Он будет хранить 3 переменные.
Шаг 4) Создайте статический метод, который генерирует и возвращает тестовые данные.
Code Линия 32,33: Создание двумерного массива (с указанием входных параметров для сложения). Используя метод asList, мы преобразуем данные в тип List, поскольку возвращаемый тип метода input — Collection.
Code Линия 30: Посмотрите на график @ Параметры аннотация для создания набора входных данных для запуска нашего теста.
Статический метод, обозначенный аннотацией @Parameters, возвращает коллекцию, где каждая запись в коллекции будет представлять собой входные данные для одной итерации теста. Рассмотрим элемент {1,2,3}. Здесь:
- firstNumber = 1
- secondNumber = 2
- expectedResult = 3
Здесь каждый элемент массива будет передаваться в конструктор по одному, поскольку класс создается несколько раз. Таким образом, пять массивов, объявленных в примере, приводят к следующим пяти запускам:
| итерация | первый номер | второй номер | ожидаемый результат | Консольная линия |
|---|---|---|---|---|
| [0] | 1 | 2 | 3 | Сумма Numbers = : 3 |
| [1] | 11 | 22 | 33 | Сумма Numbers = : 33 |
| [2] | 111 | 222 | 333 | Сумма Numbers = : 333 |
| [3] | 10 | 9 | 19 | Сумма Numbers = : 19 |
| [4] | 100 | 9 | 109 | Сумма Numbers = : 109 |
Шаг 5) Полный код.
Code Объяснение:
- Code Линия 25: Для настройки ресурсов (здесь Airthematic.class) используется аннотация @Before. Аннотация @Before используется для запуска перед каждым тестовым случаем. Она содержит предварительное условие теста.
- Code Линия 36: Для создания теста используем аннотацию @Test.
- Code Линия 39: Процесс создания утверждение проверить, соответствует ли наша сумма нашим ожиданиям.
Шаг 6) Создайте класс-исполнитель для запуска параметризованного теста:
Code Объяснение:
- Code Линия 8: Объявление основного метода класса Test, который будет запускать наш код. JUnit тест.
- Code Линия 9: Выполнение тестовых случаев с использованием JUnitCore.runClasses, которая принимает в качестве параметра имя тестового класса (в нашем примере мы используем AirthematicTest.class).
- Code Линия 11: Обработка результата с помощью цикла for и вывод на экран сообщения об ошибке.
- Code Линия 13: Распечатка успешного результата.
Выход:
Вот результат, подтверждающий успешное проведение теста без сбоев. tracт. е., как указано ниже. Обратите внимание, что JUnit В представлении отображается только одна запись на строку данных, а не один тест:
Результат отображается в консоли, где показано сложение двух чисел:
Параметризованные тесты в JUnit 5 с @ParameterizedTest
Приведенный выше пример написан для JUnit 4. JUnit В версии 5 (Jupiter) полностью отказались от модели запуска, поэтому аннотация `@RunWith(Parameterized.class)`, конструктор данных и поля экземпляра исчезли. JUnit Приведенный выше код (см. пункт 4) не устарел: он по-прежнему работает без изменений. JUnit Платформа использует старый движок. Однако новые тесты обычно пишутся с аннотацией `@ParameterizedTest`.
Требуются две зависимости: junit-jupiter-api для аннотаций к тестам и junit-jupiter-params для параметризованной поддержки. Без второго артефакта исходные аннотации вообще не будут разрешаться.
import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; class AirthematicTest { // one row per iteration, no constructor and no runner @ParameterizedTest(name = "{0} + {1} = {2}") @CsvSource({"1, 2, 3", "11, 22, 33", "111, 222, 333", "10, 9, 19", "100, 9, 109"}) void sumOfTwoNumbers(int firstNumber, int secondNumber, int expectedResult) { assertEquals(expectedResult, new Airthematic().sum(firstNumber, secondNumber)); } }
Jupiter предлагает несколько источников аргументации, и правильный из них зависит от формы данных:
| Аннотация источника | Дополнительно | Используйте это, когда |
|---|---|---|
| @ValueSource | Один столбец литералов | Для проверки требуется ровно один аргумент. |
| @CsvSource | Встроенные строки, разделенные запятыми | Небольшие таблицы чисел и строк считываются в файле без проблем. |
| @CsvFileSource | Строки, считанные из CSV-файла, находящегося в тестовом пути к классам. | Набор данных большой или поддерживается вне кода. |
| @MethodSource | Статическая фабрика, возвращающая поток аргументов. | Необходимы реальные объекты, вычисленные значения или случайные данные. |
| @EnumSource | Константы перечисления | Каждое значение перечисления должно быть использовано. |
Большинство новичков сталкиваются с двумя правилами. Аннотация `@Test`, размещенная на простом методе, молча игнорируется, поэтому метод должен содержать аннотацию `@ParameterizedTest`. И пустое значение без кавычек в `@CsvSource` читается как `null`, а пустое значение в кавычках — как пустая строка.
JUnit В этой статье используются 4 аннотации, которые отображаются в Jupiter следующим образом: @RunWith(Parameterized.class) становится @ParameterizedTest плюс аннотация источника, @Parameters становится @MethodSource или @CsvSource, а @Before становится @BeforeEach. Полный список приведен в [ссылка на статью]. JUnit аннотации учебное пособие.
Преимущества и ограничения параметризованных тестов
Параметризация не бесплатна. Она устраняет дублирование, но также ограничивает возможности написания тестов, поэтому стоит изучить обе стороны вопроса, прежде чем преобразовывать существующий набор тестов.
Преимущества
- Less дублирование: Один из методов заменяет блок практически идентичных операторов assert, как показано на первом скриншоте в этой статье.
- Более дешевое страховое покрытие: Добавление граничного случая требует добавления одной строки данных вместо создания совершенно новой строки. прецедент метод.
- Точная отчетность: Каждая итерация отображается отдельно, поэтому... JUnit В представлении точно указывается, в какой именно строке произошел сбой, а не фиксируется один общий сбой.
- Централизованные данные: Входные данные хранятся в одном методе и впоследствии могут быть перемещены в CSV-файл или фабрику без изменения утверждений.
Ограничения
- Одна из форм утверждения: Для каждой строки выполняются одни и те же проверки, поэтому сценарий, требующий различных проверок, по-прежнему нуждается в собственном методе тестирования.
- Область применения на уровне класса в JUnit 4: Исполнитель параметризует весь класс, поэтому несвязанные методы @Test в этом классе также выполняются один раз для каждой строки.
- Нечитаемые отчеты: Без шаблона имени ошибки отображаются как testAirthematicTest[3], что ничего не говорит о данных, которые привели к ошибке.
- Обширные встроенные данные: Большие массивы занимают место в логике тестирования; переместите их в фабрику @CsvFileSource или @MethodSource.
Распространенные ошибки в JUnit Параметризованные тесты
Большинство ошибок параметризации представляют собой ошибки инициализации, возникающие до выполнения хотя бы одного утверждения. В таблице ниже перечислены наиболее часто встречающиеся сообщения и причины их возникновения.
| Сообщение | Вызывать | фиксированный |
|---|---|---|
| Тестовый класс должен иметь ровно один публичный конструктор. | Класс не объявляет ни одного открытого конструктора, или объявляет два открытых конструктора. | Используйте один публичный конструктор, параметры которого соответствуют столбцам данных. |
| В классе отсутствует открытый статический метод для работы с параметрами. | Метод с аннотацией `@Parameters` не является `public static` или возвращает неверный тип. | Объявите его как public static Collection и верните Arrays.asList(…) |
| IllegalArgumentException: неверное количество аргументов | Строка может быть шире или уже, чем список параметров конструктора. | Сделайте ширину каждого массива в коллекции равной ширине конструктора. |
| Ошибка конфигурации: отсутствуют аргументы поставщика. | В тесте Jupiter используется аннотация `@ParameterizedTest` без аннотации `source`. | Добавьте @ValueSource, @CsvSource, @CsvFileSource, @MethodSource или @EnumSource. |
| Аннотация источника, по всей видимости, ничего не делает. | Метод аннотирован как @Test вместо @ParameterizedTest. | Замените @Test на @ParameterizedTest и импортируйте junit-jupiter-params. |
Ещё одна ловушка — это разделяемое состояние. Потому что JUnit Создается новый экземпляр для каждой строки, все, что хранится в статическом поле, сохраняется в каждой итерации, а значение, записанное в строке [0], может незаметно изменить результат строки [4]. Сохраняйте состояние каждой строки в полях экземпляра и сбрасывайте общие ресурсы в методе @Before или @BeforeEach. Общие рекомендации по изоляции тестов описаны в модульное тестирование учебное пособие.









