Общая идея параметризованных модульных тестов — запускать один и тот же метод тестирования для разных данных. Создание параметризованных тестов в JUnit 4 далеко от совершенства. Существует много проблем с существующей архитектурой: параметры определяются как поля класса, и для их создания требуется конструктор, параметризованные и непараметрические тесты нельзя смешивать в одном классе тестов, а встроенные источники данных очень ограничены. К счастью, все это улучшено в JUnit 5!
Примечание. В качестве альтернативы параметризованному тесту JUnit 4 вы можете использовать библиотеку JUnitParams, которая решает многие из упомянутых мною проблем (см. Мой пост в блоге о JUnitParams здесь: http://blog.codeleak.pl/2013/12/parametrized-junit- tests-with.html ).
С чего начать?
Чтобы начать работу с параметризованными тестами в Junit 5, вам необходимо добавить в проект необходимую зависимость: добавьте org.junit.jupiter:junit-jupiter-params:${junitJupiterVersion}
зависимость от проекта для использования параметризованных тестов, поставщиков аргументов и конвертеров. ,
SUT — тестируемая система
Все созданные мной образцы тестируют класс FizzBuzz:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
public class FizzBuzz { private static final int THREE = 3 ; private static final int FIVE = 5 ; public String calculate( int number) { if (isDivisibleBy(number, THREE) && isDivisibleBy(number, FIVE)) { return "FizzBuzz" ; } if (isDivisibleBy(number, THREE)) { return "Fizz" ; } if (isDivisibleBy(number, FIVE)) { return "Buzz" ; } return String.valueOf(number); } private static boolean isDivisibleBy( int dividend, int divisor) { return dividend % divisor == 0 ; } } |
Хотя FizzBuzz действительно прост, его также можно использовать для демонстрации более продвинутых методов модульного тестирования, таких как реализация параметризованных тестов.
Мой первый параметризованный тест в JUnit 5
Чтобы создать параметризованный тест в JUnit 5, аннотируйте метод теста с помощью @org.junit.jupiter.params.ParameterizedTest
(вместо @Test
) и предоставьте источник аргумента:
1
2
3
4
5
|
@ParameterizedTest (name = "{index} => calculate({0})" ) @ValueSource (ints = { 1 , 2 , 4 , 7 , 11 , 13 , 14 }) public void returnsNumberForNumberNotDivisibleByThreeAndFive( int number, TestInfo testInfo) { assertThat(fizzBuzz.calculate(number)).isEqualTo( "" + number); } |
У аннотации есть необязательный атрибут name
который используется для настройки отображаемых имен вызовов. Доступные переменные шаблона: {index} -> текущий индекс вызова (на основе 1), {arguments} -> полный список аргументов через запятую, {0}, {1},… -> отдельный аргумент.
В этом примере @org.junit.jupiter.params.provider.ValueSource
предоставляет доступ к массиву литеральных значений целых чисел. В этой аннотации должен быть указан только один тип ввода (строки, вставки, длинные или двойные).
Я также предоставляю дополнительные параметры, разрешенные с помощью org.junit.jupiter.api.extension.ParameterResolver
. Обратите внимание, что параметры метода, которые разрешаются источниками аргументов, должны стоять на первом месте в списке аргументов.
Больше источников аргументов
@MethodSource
1
2
3
4
5
|
@ParameterizedTest (name = "{index} => calculate({0})" ) @MethodSource (names = { "divisibleByThree" , "divisibleByThreeButNotFive" }) void returnFizzForNumberDivisibleByThree( int number) { assertThat(fizzBuzz.calculate(number)).isEqualTo( "Fizz" ); } |
@org.junit.jupiter.params.provider.MethodSource
ссылается на методы (1 или более), возвращающие источник аргумента. В этом примере есть два метода:
1
2
3
4
5
6
7
8
9
|
private static Stream<Integer> divisibleByThree() { int [] ints = new int []{ 18 , 21 }; return Stream.of( 3 , 6 , 9 , 12 ); } // The returned array will be converted to a Stream private static String[] divisibleByThreeButNotFive() { return new String[]{ "18" , "21" }; } |
Метод, который предоставляет аргументы, должен быть статическим, не должен принимать аргументов и должен возвращать либо Stream, Iterable, Iterator, либо массив. Вероятно, вы заметили, что метод divisibleByThreeButNotFive()
возвращает массив строк. Это будет прекрасно работать благодаря встроенным конвертерам неявных аргументов . Это действительно полезно, когда источником аргумента является CSV (подробнее об этом ниже). Кроме того, аргументы можно конвертировать с помощью пользовательских конвертеров аргументов.
Для разрешения нескольких аргументов источник метода возвратит поток экземпляров org.junit.jupiter.params.provider.ObjectArrayArguments
( org.junit.jupiter.params.provider.ObjectArrayArguments
):
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
@ParameterizedTest (name = "{index} => calculate({0}) should return {1}" ) @MethodSource (names = { "fizzBuzz" }) void fizzBuzz( int number, String expectedResult) { assertThat(fizzBuzz.calculate(number)).isEqualTo(expectedResult); } private static Stream<Arguments> fizzBuzz() { return Stream.of( ObjectArrayArguments.create( 1 , "1" ), ObjectArrayArguments.create( 2 , "2" ), ObjectArrayArguments.create( 3 , "Fizz" ), ObjectArrayArguments.create( 4 , "4" ), ObjectArrayArguments.create( 5 , "Buzz" ), ObjectArrayArguments.create( 6 , "Fizz" ), ObjectArrayArguments.create( 7 , "7" ), ObjectArrayArguments.create( 8 , "8" ), ObjectArrayArguments.create( 9 , "Fizz" ), ObjectArrayArguments.create( 15 , "FizzBuzz" ) ); } |
@CsvFileSource
Другой очень интересный способ предоставления источника аргумента — org.junit.jupiter.params.provider.CsvFileSource
который предоставляет аргументы из одного или нескольких CSV-файлов из classpath:
1
2
3
4
5
|
@ParameterizedTest (name = "{index} => calculate({0}) should return {1}" ) @CsvFileSource (resources = { "/fizzbuzz/fizzbuzz_1.csv" , "/fizzbuzz/fizzbuzz_2.csv" }, delimiter = ';' ) void fizzBuzzCsv( int number, String expectedResult) { assertThat(fizzBuzz.calculate(number)).isEqualTo(expectedResult); } |
Другие источники аргументов
-
@EnumSource
предоставляет удобный способ использования констант Enum. -
@CsvSource
позволяет вам выражать списки аргументов как значения, разделенные запятыми -
@ArgumentsSource
может использоваться для указания настраиваемого поставщика аргументов для повторного использования.
Наслаждайтесь параметризованными тестами в JUnit 5!
Ресурсы
Все примеры, представленные в этой статье, можно найти на GitHub: https://github.com/kolorobot/unit-testing-demo.
Посмотрите официальную документацию JUnit 5, чтобы узнать больше: http://junit.org/junit5/docs/current/user-guide/#writing-tests-parameterized-tests
Ссылка: | Более четкие параметризованные тесты с JUnit 5 от нашего партнера JCG Рафаля Боровца в блоге Codeleak.pl . |