问题
I am attempting to write a parameterized test for an interface Foo, which declares a method getFooEventInt(int, int). I have written a paramterized test that works for a single instance of Foo (a FooImpl object).
public class FooTest {
@ParameterizedTest
@MethodSource("getFooEvenIntProvider")
public void getFooEvenIntTest(int seed, int expectedResult) {
Foo foo = new FooImpl();
Assertions.assertEquals(expectedResult, foo.getFooEvenInt(seed));
}
private static Stream getFooEvenIntProvider() {
return Stream.of(
Arguments.of(-2, 0),
Arguments.of(-1, 0),
Arguments.of( 0, 2),
Arguments.of( 1, 2),
);
}
}
However, I'd like to be able to have getFooEvenIntTest(int, int) be invoked against a provided list of Foo implementation instances, with each iteration then using the provide list of seed/expectedResult values.
I realize I could do this as...
public class FooTest {
@ParameterizedTest
@MethodSource("getFooProvider")
public void getFooImplEvenIntTest(Foo foo) {
int[] expectedResult = { 0, 0, 2, 2 };
int[] seed = { -2, -1, 0, 1 };
for(int i=0; i<seed.length; i++) {
Assertions.assertEquals(expectedResult[i],
foo.getFooEvenInt(seed[i]));
}
}
private static Stream getFooProvider() {
return Stream.of(
Arguments.of(new FooImpl()),
Arguments.of(new FooImpl2())
);
}
}
Any ideas? I'll post if I figure it out, but I thought I'd check to see if this is even doable, or if there's a different approach.
回答1:
BLUF: I will interpret the crickets to mean "even if you could, you shouldn't be nesting parameterized tests", in which case I run with the approach outlined below.
For an interface Foo...
public interface Foo {
public char getFirstChar(String strValue);
public int getNextEvenInt(int seed);
}
The "best" use of parameterized tests for implementations of Foo would be...
public class FooTest {
@ParameterizedTest
@MethodSource("getFooProvider")
public void getFirstCharTest(Foo foo) {
char[] expectedResult = { 'a', 'b', 'c', 'd' };
String[] seed = { "alpha", "bravo", "charlie", "delta" };
for(int i=0; i<seed.length; i++) {
Assertions.assertEquals(expectedResult[i],
foo.getFirstChar(seed[i]));
}
}
@ParameterizedTest
@MethodSource("getFooProvider")
public void getNextEvenIntTest(Foo foo) {
int[] expectedResult = { 0, 0, 2, 2 };
int[] seed = { -2, -1, 0, 1 };
for(int i=0; i<seed.length; i++) {
Assertions.assertEquals(expectedResult[i],
foo.getFooEvenInt(seed[i]));
}
}
private static Stream getFooProvider() {
return Stream.of(
Arguments.of(new FooImplOne()),
Arguments.of(new FooImplTwo())
// extend as need for implementations of Foo
);
}
}
While I won't get the "warm fuzzies" of seeing the passing results for each value-pair in the various tests, it will fulfill my goal of having a test at the interface level that I can easily extend to validate/verify the interface's implementations.
回答2:
I guess you think of combining two arguments streams. You could achieve this by creating the cartesian product of two arguments lists.
I have implemented that on https://github.com/joerg-pfruender/junit-goodies/blob/master/src/main/java/com/github/joergpfruender/junitgoodies/ParameterizedTestHelper.java
public static Stream<Arguments> cartesian(Stream a, Stream b) {
List argumentsA = (List) a.collect(Collectors.toList());
List argumentsB = (List) b.collect(Collectors.toList());
List<Arguments> result = new ArrayList();
for (Object o : argumentsA) {
Object[] objects = asArray(o);
for (Object o1 : argumentsB) {
Object[] objects1 = asArray(o1);
Object[] arguments = ArrayUtils.addAll(objects, objects1);
result.add(Arguments.of(arguments));
}
}
return result.stream();
}
private static Object[] asArray(Object o) {
Object[] objects;
if (o instanceof Arguments) {
objects = ((Arguments) o).get();
} else {
objects = new Object[]{o};
}
return objects;
}
Then your test code will be:
public static Stream<Arguments> fooIntsAndFooProvider() {
return ParameterizedTestHelper.cartesian(getFooEvenIntProvider(), getFooProvider());
}
@ParameterizedTest
@MethodSource("fooIntsAndFooProvider")
public void getFooImplEvenIntTest(Integer seed, Integer expectedResult, Foo foo) {
Assertions.assertEquals(expectedResult,
foo.getFooEvenInt(seed));
}
来源:https://stackoverflow.com/questions/53327761/is-it-possible-to-nest-junit-5-parameterized-tests