- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在JUnit 4中,使用 @Parameterized
批注很容易在一系列类中测试不变式。关键是要针对单个参数列表运行一组测试。
如何在不使用JUnit-vintage的情况下在JUnit 5中复制它?
@ParameterizedTest
不适用于测试类。 @TestTemplate
听起来似乎很合适,但是注释的目标也是一种方法。
此类JUnit 4测试的示例是:
@RunWith( Parameterized.class )
public class FooInvariantsTest{
@Parameterized.Parameters
public static Collection<Object[]> data(){
return new Arrays.asList(
new Object[]{ new CsvFoo() ),
new Object[]{ new SqlFoo() ),
new Object[]{ new XmlFoo() ),
);
}
private Foo fooUnderTest;
public FooInvariantsTest( Foo fooToTest ){
fooUnderTest = fooToTest;
}
@Test
public void testInvariant1(){
...
}
@Test
public void testInvariant2(){
...
}
}
最佳答案
JUnit 5中的参数化测试功能无法提供与JUnit 4完全相同的功能。
引入了具有更大灵活性的新功能...但是它也丢失了JUnit4功能,在该功能中,参数化测试类在类级别使用适用于该类所有测试方法的参数化夹具/断言。
因此需要通过指定“输入”为每种测试方法定义@ParameterizedTest
。
除了上述不足之外,我还将介绍两个版本之间的主要区别以及如何在JUnit 5中使用参数化测试。
TL; DR
要编写参数化测试以按大小写指定值以测试您的问题,
org.junit.jupiter.params.provider.MethodSource
应该可以完成这项工作。
@MethodSource
allows you to refer to one or more methods of the test class. Each method must return aStream
,Iterable
,Iterator
, or array of arguments. In addition, each method must not accept any arguments. By default such methods must be static unless the test class is annotated with@TestInstance(Lifecycle.PER_CLASS)
.If you only need a single parameter, you can return instances of the parameter type directly as demonstrated by the following example.
@MethodSource
依赖于工厂方法,也可以用于指定多个参数的测试方法。
@Parameters
public static Collection<Object[]> data() {
private static Stream<Arguments> data() {
Collection<Object[]>
成为Stream<Arguments>
,可提供更大的灵活性。 @Parameters
声明一个并且只有一个工厂方法。@MethodSource("..")
注释的测试方法,这些方法引用了不同的工厂方法。 import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.api.Assertions;
public class ParameterizedMethodSourceWithArgumentsTest {
@ParameterizedTest
@MethodSource("addFixture")
void add(int a, int b, int result) {
Assertions.assertEquals(result, a + b);
}
private static Stream<Arguments> addFixture() {
return Stream.of(
Arguments.of(1, 2, 3),
Arguments.of(4, -4, 0),
Arguments.of(-3, -3, -6));
}
}
@MethodSource
。@MethodSource
有一些优点,但也有一些缺点。Parameterized tests make it possible to run a test multiple times with different arguments. They are declared just like regular
@Test
methods but use the@ParameterizedTest
annotation instead. In addition, you must declare at least one source that will provide the arguments for each invocation.
junit-jupiter-engine
核心依赖项未包含参数化测试功能。junit-jupiter-params
。<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.0.0</version>
<scope>test</scope>
</dependency>
@ValueSource
@EnumSource
@MethodSource
@CsvSource
@CsvFileSource
@ArgumentsSource
@MethodSource
@ValueSource
@CsvSource
@EnumSource
,@ArgumentsSource
和@CsvFileSource
当然可能会有所帮助,但它们更加专业。@MethodSource
,@ValueSource
和@CsvSource
@MethodSource
@MethodSource
是一个很好的选择。@MethodSource("methodName")
注释测试方法,其中methodName
是此数据源方法的名称。import java.util.stream.Stream;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
public class ParameterizedMethodSourceTest {
@ParameterizedTest
@MethodSource("getValue_is_never_null_fixture")
void getValue_is_never_null(Foo foo) {
Assertions.assertNotNull(foo.getValue());
}
private static Stream<Foo> getValue_is_never_null_fixture() {
return Stream.of(new CsvFoo(), new SqlFoo(), new XmlFoo());
}
}
@MethodSource
也是一个很好的选择。org.junit.jupiter.params.provider.Arguments
流。import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.api.Assertions;
public class ParameterizedMethodSourceWithArgumentsTest {
@ParameterizedTest
@MethodSource("getFormatFixture")
void getFormat(Foo foo, String extension) {
Assertions.assertEquals(extension, foo.getExtension());
}
private static Stream<Arguments> getFormatFixture() {
return Stream.of(
Arguments.of(new SqlFoo(), ".sql"),
Arguments.of(new CsvFoo(), ".csv"),
Arguments.of(new XmlFoo(), ".xml"));
}
}
@ValueSource
@ValueSource
的参数源。@ValueSource
确实定义了以下属性:String[] strings() default {};
int[] ints() default {};
long[] longs() default {};
double[] doubles() default {};
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
public class ParameterizedValueSourceTest {
@ParameterizedTest
@ValueSource(ints = { 1, 2, 3 })
void sillyTestWithValueSource(int argument) {
Assertions.assertNotNull(argument);
}
}
String
类型尤其可以通过其解析将其转换为多种其他类型。@CsvSource
@CsvSource
。@CsvSource
注释测试,并在每种情况下在String
数组中指定。@ValueSource
一样,方法的源和参数之间的映射可以在两种不同的类型之间完成。import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
public class ParameterizedCsvSourceTest {
@ParameterizedTest
@CsvSource({ "12,3,4", "12,2,6" })
public void divideTest(int n, int d, int q) {
Assertions.assertEquals(q, n / d);
}
}
@CsvSource
VS @MethodSource
@CsvSource
具有一些优点:它更清晰,更短。String
数组。该框架提供了转换功能,但受到限制。String
和测试方法的参数具有相同的类型(String
-> String
)或依赖于内置转换(例如String
-> int
),但@CsvSource
似乎是使用方式。@CsvSource
和工厂方法执行的转换创建自定义转换器(ArgumentConverter
子类),从而保持@MethodSource
的灵活性。Stream<Arguments>
。它具有上述缺点,但从源到参数的任何类型的开箱即用映射也具有很大的好处。@CsvSource
或@ValueSource
)和测试方法的参数之间的映射,如所看到的,如果类型不同,则框架允许进行一些转换。3.13.3. Argument Conversion
Implicit Conversion
To support use cases like
@CsvSource
, JUnit Jupiter provides a number of built-in implicit type converters. The conversion process depends on the declared type of each method parameter......
String
instances are currently implicitly converted to the following target types.Target Type | Example
boolean/Boolean | "true" → true
byte/Byte | "1" → (byte) 1
char/Character | "o" → 'o'
short/Short | "1" → (short) 1
int/Integer | "1" → 1
.....
String
和定义为参数的int
之间进行了隐式转换:@CsvSource({ "12,3,4", "12,2,6" })
public void divideTest(int n, int d, int q) {
Assertions.assertEquals(q, n / d);
}
String
源到LocalDate
参数的隐式转换:@ParameterizedTest
@ValueSource(strings = { "2018-01-01", "2018-02-01", "2018-03-01" })
void testWithValueSource(LocalDate date) {
Assertions.assertTrue(date.getYear() == 2018);
}
ArgumentConverter
。Explicit Conversion
Instead of using implicit argument conversion you may explicitly specify an
ArgumentConverter
to use for a certain parameter using the@ConvertWith
annotation like in the following example.
ArgumentConverter
的客户端提供引用实现。Explicit argument converters are meant to be implemented by test authors. Thus, junit-jupiter-params only provides a single explicit argument converter that may also serve as a reference implementation:
JavaTimeArgumentConverter
. It is used via the composed annotationJavaTimeConversionPattern
.
@ParameterizedTest
@ValueSource(strings = { "01.01.2017", "31.12.2017" })
void testWithExplicitJavaTimeConverter(@JavaTimeConversionPattern("dd.MM.yyyy") LocalDate argument) {
assertEquals(2017, argument.getYear());
}
JavaTimeArgumentConverter
转换器类:package org.junit.jupiter.params.converter;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.OffsetTime;
import java.time.Year;
import java.time.YearMonth;
import java.time.ZonedDateTime;
import java.time.chrono.ChronoLocalDate;
import java.time.chrono.ChronoLocalDateTime;
import java.time.chrono.ChronoZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalQuery;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import org.junit.jupiter.params.support.AnnotationConsumer;
/**
* @since 5.0
*/
class JavaTimeArgumentConverter extends SimpleArgumentConverter
implements AnnotationConsumer<JavaTimeConversionPattern> {
private static final Map<Class<?>, TemporalQuery<?>> TEMPORAL_QUERIES;
static {
Map<Class<?>, TemporalQuery<?>> queries = new LinkedHashMap<>();
queries.put(ChronoLocalDate.class, ChronoLocalDate::from);
queries.put(ChronoLocalDateTime.class, ChronoLocalDateTime::from);
queries.put(ChronoZonedDateTime.class, ChronoZonedDateTime::from);
queries.put(LocalDate.class, LocalDate::from);
queries.put(LocalDateTime.class, LocalDateTime::from);
queries.put(LocalTime.class, LocalTime::from);
queries.put(OffsetDateTime.class, OffsetDateTime::from);
queries.put(OffsetTime.class, OffsetTime::from);
queries.put(Year.class, Year::from);
queries.put(YearMonth.class, YearMonth::from);
queries.put(ZonedDateTime.class, ZonedDateTime::from);
TEMPORAL_QUERIES = Collections.unmodifiableMap(queries);
}
private String pattern;
@Override
public void accept(JavaTimeConversionPattern annotation) {
pattern = annotation.value();
}
@Override
public Object convert(Object input, Class<?> targetClass) throws ArgumentConversionException {
if (!TEMPORAL_QUERIES.containsKey(targetClass)) {
throw new ArgumentConversionException("Cannot convert to " + targetClass.getName() + ": " + input);
}
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
TemporalQuery<?> temporalQuery = TEMPORAL_QUERIES.get(targetClass);
return formatter.parse(input.toString(), temporalQuery);
}
}
关于java - 如何在JUnit 5中实现JUnit 4参数化测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46897134/
我是一名优秀的程序员,十分优秀!