Parameterised Test Execution in JUnit Jupiter(JUnit5)

1.7k views Asked by At

Is there a way to have parameterized tests in JUnit Jupiter (Junit5)?

@RunWith(Parameterized.class)

Background:

I went through How to write junit tests for interfaces? and wanted to implement test cases as answered here using JUnit5. But couldn't find the same class/es in the Jupiter package.

Attempts:

Looking further for substitutes I found that Extensions would be replacing the @RunWith as stated in Migrating tips

@RunWith no longer exists; superseded by @ExtendWith.

I tried defining a CustomExtension as provided in the sample here - MockitoExtension but couldn't succeed in getting to use the instances of classes Parameterized.

Looking forward to suggestions on how to test interfaces with parameterized instances of classes implementing it in JUnit5.

4

There are 4 answers

0
Marc Philipp On BEST ANSWER

JUnit 5 M4 was just released and now supports parameterized tests.

Here's the "Hello World" example:

@ParameterizedTest
@ValueSource(strings = { "Hello", "World" })
void testWithStringParameter(String argument) {
    assertNotNull(argument);
}

Please refer to the User Guide for the full documentation and additional examples.

0
Nicolai Parlog On

As of January 9th, 2017, JUnit 5 does not support parameterized tests per se, but work on that feature is in progress. Note that you might be able to achieve something similar with dynamic tests.

That said, I would consider both bad ways to implement interface tests and JUnit Jupiter offers two better approaches:

  1. @Test annotated interface default methods will be executed. So if you have a production interface Interface you can write an interface InterfaceTest that uses default methods to test everything you want. For every Impl implements Interface you can then write an ImplTest implements InterfaceTest.
  2. If you need more flexibility and would like to implement the tests for Interface in an abstract class AbstractInterfaceTest you can do that as well and then have a nested test class in your ImplTest that extends AbstractInterfaceTest.

Both of these approaches ensure that the test for the interface does not know the classes implementing the interface, which is a huge downside of the answer you linked to.

0
Maciej Kowalski On

In my projects i have been using this library:

https://github.com/TNG/junit-dataprovider/

in order to add parameterization to my JUnit tests. I have been using version 4.x but was never a fan of the embedded parameterization it provided. If you are familiar with TestNg's @DataProvider then this extension is not much different.

Check it out as see if it will be of any benefit to you as it was for me and my team. Frankly i could not imagine working without it now.

0
Anton Balaniuc On

You can use dynamic tests for that:

@TestFactory
Stream<DynamicTest> params() {

        return Stream.of(new double[][]{{2d, 4d}, {3d, 9d}, {4d, 16d}}).
                map(i ->
                        dynamicTest("Square root test " + Arrays.toString(i),
                                () -> assertEquals(i[0], Math.sqrt(i[1]))
                        )
                );
}