1

I have a Junit5 parameterised test method and I need to use my custom DataProvider class with methods that return Stream<Arguments> and are supposed to pass all their arguments to this test method altogether. The test method itself has the following signature:

public void testAllSteps(String section, String subsection, String rangeFilterName, String min, String max, String ListFilterName, List<String> values, int number)

and DataProvider contains the following methods:

public static Stream<String> sectionProvider() {
    return Stream.of("Electronics", "Laptops");
}

public static Stream<String> rangeFilterProvider() { 
    return Stream.of("Price", "10000", "30000"); 
}

 
public static Stream<Arguments> listFilterProvider() {
    return Stream.of(
            Arguments.of("Manufacturer", List.of("HP, Lenovo")))
    );
}

public static Stream<Arguments> conditionNumberProvider() { 
    return Stream.of(Arguments.of(12)) 
}

Thus sectionProvider() provides values for section and subsection parameters, and the other ones provide values for the other respective parameters. Such segregation is due to grouping the arguments into logic groups.

I know that I can state multiple methods in the @MethodSource annotation for parameterising the method, which I tried to do, like this:

  @MethodSource({"utils.DataProvider#sectionProvider", "utils.DataProvider#rangeFilterProvider", "utils.DataProvider#listFilterProvider", "utils.DataProvider#conditionNumberProvider"})

but my program seems to fail to do that, saying the following:

org.junit.jupiter.api.extension.ParameterResolutionException: No ParameterResolver registered for parameter [java.lang.String arg1] in method [public void market.MarketTest.testAllSteps(java.lang.String,java.lang.String,java.lang.String,java.lang.String,java.lang.String,java.lang.String,java.util.List<java.lang.String>,int)].

I'm still kinda new to Junit5 parameterised testing, and I don't how pass all this data to my test method altogether.

I suspect I'll have to split my test method implementation into multiple methods (since it's presented in Allure steps) so I can provide a separate portion of arguments to each of them, and it will work, but according to the whole task I was given, it's not the right thing to do.

Maybe you have some ideas to share?

I tried to use a method that combines all Streams of Arguments into one but that also resulted into an error.

Also I tried to reduce the number of arguments in my test by grouping them into collections so it would be equal to the number of provider methods in the @MethodSource statement, but it made some code in other classes really clumsy, and I wasn't sure it could help, so I refused that idea before completing.

2 Answers 2

0

Here is a little snippet of test that combines 3 Arguments into one.

public class AppTest {

    @ParameterizedTest
    @MethodSource("all")
    public void test(String a, String b, String c) {
        System.out.printf("a = %s b = %s c = %s%n", a, b, c);
    }

    public static Stream<Arguments> first() {
        return Stream.of(
                Arguments.arguments("f1"),
                Arguments.arguments("f2"),
                Arguments.arguments("f3")
        );
    }

    public static Stream<Arguments> second() {
        return Stream.of(
                Arguments.arguments("s1"),
                Arguments.arguments("s2"),
                Arguments.arguments("s3")
        );
    }

    public static Stream<Arguments> third() {
        return Stream.of(
                Arguments.arguments("t1"),
                Arguments.arguments("t2"),
                Arguments.arguments("t3")
        );
    }

    public static Stream<Arguments> all() {
        return zipArguments(first(), second(), third());
    }

    private static Stream<Arguments> zipArguments(Stream<Arguments> first, Stream<Arguments>... other) {
        return Stream.of(other)
                .reduce(first, AppTest::zipArguments);
    }

    private static Stream<Arguments> zipArguments(Stream<Arguments> first, Stream<Arguments> second) {
        return zip(first, second, (f, s) ->
                Arguments.of(Stream.concat(
                                Arrays.stream(f.get()),
                                Arrays.stream(s.get()))
                        .toArray(Object[]::new)));
    }

    public static <L, R, T> Stream<T> zip(Stream<L> leftStream, Stream<R> rightStream, BiFunction<L, R, T> combiner) {
        Spliterator<L> lefts = leftStream.spliterator();
        Spliterator<R> rights = rightStream.spliterator();
        return StreamSupport.stream(new Spliterators.AbstractSpliterator<T>(Long.min(lefts.estimateSize(), rights.estimateSize()), lefts.characteristics() & rights.characteristics()) {
            @Override
            public boolean tryAdvance(Consumer<? super T> action) {
                return lefts.tryAdvance(left -> rights.tryAdvance(right -> action.accept(combiner.apply(left, right))));
            }
        }, false);
    }
}
Sign up to request clarification or add additional context in comments.

Comments

-1

May be reading this would help you: https://www.baeldung.com/parameterized-tests-junit-5

For example:

@MethodSource("utils.DataProvider#paramProvider")
public void testAllSteps(String section, String subsection, String rangeFilterName, String min, String max, String ListFilterName, List<String> values, int number)

then you can provide the params like this,

public static Stream<String> paramProvider() {
    return Stream.of(
            Arguments.of(
                    "Electronics",
                    "Laptops",
                    "Price",
                    "10000",
                    "30000",
                    "Manufacturer",
                    List.of("HP, Lenovo"),
                    12
            )
    );
}

2 Comments

That's the way I initially did it, but the task turned out to be requiring not to put all the arguments in a single set, but to separate them into logical groups. I'm thinking about using the initial approach with a set of "Arguments.of" methods but I don't think it's the right thing as well.
The logical group should be the set of arguments Arguments.of(...). Usually parts of method parameters are not considered as a logical group. If it's a logical group it should be defined as an object in OOP world. @MethodSource({"utils.DataProvider#sectionProvider", "utils.DataProvider#rangeFilterProvider", "utils.DataProvider#listFilterProvider", "utils.DataProvider#conditionNumberProvider"}) This will not work. The test method will run for each provider method defined in method source. It will not combine the output from all the methods like you seem to expect.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.