Issue
I'm trying to parameterize this test:
@Test
public void reverseQuote(double[] qsp) throws Exception {
...}
It seems absurd to me that it doesn't exists some quick method to initialize array qsp
like, for example, ValueSource
:
@ParameterizedTest
@ValueSource(ints = { 1, 2, 3 })
void testWithValueSource(int argument) {
assertNotNull(argument);
}
my aim is to do something like @ValueSource(doublesArray = {new double[]{1.0, 2.0, 3.0}})
(that now returns error). Doesn't exists anything that permits something similar??
Other answers seem to suggest only elaborated ways, like using @MethodSource
or @ConvertWith
.
I accept answers implementing other testing libraries, too.
Solution
Ok, this is gonna be a weird answer, but it works and it was kinda fun to do.
First thing: your way is impossible. Not because of JUnit or any related API, but because of Java - valid annotation type elements (annotation arguments can only be primitive, String, Class, Enum, other annotation and array of all those).
Second thing: we can get around the first one. Check this:
@ArraySources(
arrays = {
@ArraySource(array = {1, 2, 3}),
@ArraySource(array = {4, 5, 6}),
@ArraySource(array = {7, 8, 9})
}
)
As it says, annotation can have other annotations as arguments, and arrays of those, so we are using those 2 rules here.
Third thing: how does that help? We can add our own annotation + argument provider, JUnit 5 is expansible in that way.
Both annotations:
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@ArgumentsSource(ArrayArgumentsProvider.class)
public @interface ArraySources {
ArraySource[] arrays();
}
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ArraySource {
int[] array() default {};
}
Argument provider based on the annotations:
public class ArrayArgumentsProvider implements ArgumentsProvider, AnnotationConsumer<ArraySources> {
private List<int[]> arguments;
public void accept(ArraySources source) {
List<ArraySource> arrays = Arrays.asList(source.arrays());
this.arguments = arrays.stream().map(ArraySource::array).collect(Collectors.toList());
}
public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
return this.arguments.stream().map(Arguments::of);
}
}
And the final test using those:
public class ArraySourcesTest {
@ParameterizedTest
@ArraySources(
arrays = {
@ArraySource(array = {1, 2, 3}),
@ArraySource(array = {4, 5, 6}),
@ArraySource(array = {7, 8, 9})
}
)
void example(int[] array) {
System.out.println(Arrays.toString(array));
System.out.println("Test Over");
}
}
/* Output
[1, 2, 3]
Test Over
[4, 5, 6]
Test Over
[7, 8, 9]
Test Over
*/
You mentioned @MethodSource
as complicated, well, so I think I failed in this matter, but it works. It could be simplified and enhanced obviously (like naming annotation arguments as defaults - value - and I only did it for int
to show the idea). Not sure if you could achieve the same with existing features (ArgumentsProvider
and ArgumentSources
), but this looks more specific (you know you are working with arrays) and shows possibilities of extending JUnit5, may be useful in other case.
Answered By - Shadov
Answer Checked By - Willingham (JavaFixing Volunteer)