Параметризованные тесты JUnit5 на уровне класса
Можно ли использовать параметризованные новые функции JUnit5 для запуска тестовых классов для получения тестовых параметров вместо того, чтобы делать это на уровне метода?
С JUnit 4 бегун, такой как @RunWith(Parameterized::class)
плюс наследование может быть использовано для передачи массива параметров подклассам, но я не уверен, возможно ли достичь чего-то эквивалентного, но с использованием нового API JUnit 5.
4 ответа
В JUnit 5 есть собственный подход к параметризованным тестам, и, конечно, он отличается от JUnit 4. Новый подход не позволяет использовать параметризованные фикстуры на уровне класса, т.е. через каждый его метод тестирования. Поэтому каждый параметризованный метод тестирования должен быть явно аннотирован ссылкой на параметры.
JUnit 5 предоставляет множество типов источников параметров, которые можно найти в документации и руководствах.
В вашем случае самый простой способ перейти с @Parameters
из Junit 4 использует@MethodSource
или @ArgumentsSource
из org.junit.jupiter.params.provider.*
.
JUnit 4:
@RunWith(Parameterized.class)
public class MyTestWithJunit4 {
@Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][] {
{ 0, 0, 0 },
{ 1, 2, 3 },
{ 5, 3, 8 }
});
}
int first;
int second;
int sum;
public MyTestWithJunit4(int first, int second, int sum) {
this.first = first;
this.second = second;
this.sum = sum;
}
@Test
public void test() {
assertEquals(sum, first + second));
}
}
JUnit 5 (с @MethodSource
):
class MyTestWithJunit5 {
@DisplayName("Test with @MethodSource")
@ParameterizedTest(name = "{index}: ({0} + {1}) => {2})")
@MethodSource("localParameters")
void test(int first, int second, int sum) {
assertEquals(sum, first + second);
}
static Stream<Arguments> localParameters() {
return Stream.of(
Arguments.of(0, 0, 0),
Arguments.of(1, 2, 3),
Arguments.of(5, 3, 8)
);
}
}
JUnit 5 (с @ArgumentsSource
):
class MyTestWithJunit5 {
@DisplayName("Test with @ArgumentsSource")
@ParameterizedTest(name = "{index}: ({0} + {1}) => {2})")
@ArgumentsSource(Params.class)
void test(int first, int second, int sum) {
assertEquals(sum, first + second);
}
static class Params implements ArgumentsProvider {
@Override
public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
return Stream.of(
Arguments.of(0, 0, 0),
Arguments.of(1, 2, 3),
Arguments.of(5, 3, 8)
);
}
}
}
Считайте, что метод в @MethodSource
и класс в @ArgumentsSource
можно описать где угодно, а не только внутри того же класса, в котором расположены тестовые методы. Также@MethodSource
позволяет предоставлять несколько исходных методов, поскольку его value
это String[]
.
Некоторые замечания и сравнение
В JUnit 4 у нас мог быть только один заводской метод, обеспечивающий параметры, и предполагалось, что тесты будут построены на этих параметрах. Напротив, JUnit 5 дает больше абстракции и гибкости в параметрах привязки и отделяет логику тестирования от ее параметров, которые являются второстепенными. Это позволяет создавать тесты независимо от источников параметров и легко изменять их при необходимости.
Требование зависимости
Функция параметризованных тестов не включена в ядро junit-jupiter-engine
, но находится в отдельной зависимости junit-jupiter-params
.
Создайте мета-аннотацию, определяющую параметризацию, и примените ее к методам тестирования:
public class MyTest {
@ParameterizedTest(name = "{0}")
@MethodSource("allImplementations")
@Retention(RetentionPolicy.RUNTIME)
private @interface TestAllImplementations {
}
static Stream<Arguments> allImplementations() {
return Stream.of(
Arguments.of("Serial", new SerialWidget()),
Arguments.of("Concurrent", new ConcurrentWidget())
);
}
@TestAllImplementations
void myFirstTest(String name, Widget implementation) {
/* ... */
}
@TestAllImplementations
void mySecondTest(String name, Widget implementation) {
/* ... */
}
}
Лучшее решение, которое я смог найти, — сделать старый тест абстрактным. Затем создайте новый класс с вложенными тестами для каждого варианта, например.
public class NewParametricTest {
@Nested
public class NewParametricTestVariation1Test
extends AbstractOriginalToBeParameticizedTest {
public NewParametricTestVariation1Test() {
super("Some parameter", 1);
}
}
// add others here
}
@ParameterizedTest()
@MethodSource("dataProvider")
void testWithDataProvider(String str, List<JSONObject> list) {
System.out.println();
}
static Stream<Arguments> dataProvider() {
String json = """
{
"test":1
}
""";
return Stream.of(
arguments("abc", Arrays.asList(new JSONObject(json))),
arguments("lemon", Arrays.asList(new JSONObject(json)))
);
Я обошел эту сложность таким образом