sebastiandaschner blog
First look at JUnit 5
thursday, july 14, 2016In July the first milestone of JUnit 5 was released. This new version will make use of Java 8 lambdas and will redesign some JUnit core features.
What’s new
Some of the main changes in the way how we’ll write JUnit tests are:
- 
New package
org.junit.jupiter.api— instead of good oldorg.junit - 
@BeforeEach,@BeforeAll,@AfterEach,@AfterAll— instead of the ones known now - 
@Disabledto disable tests — instead of@Ignored - 
@ExtendedWithsupersedes@RunWithand@Rule - 
DynamicTests supersedeParameterizedtests - 
Assertions#expectThrowsfor expected exceptions 
The 5.0.0-M1 version can be used from Maven central:
<dependencies>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-engine</artifactId>
        <version>5.0.0-M1</version>
        <scope>test</scope>
    </dependency>
</dependencies>
...
<plugins>
    <plugin>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.19.1</version>
        <dependencies>
            <dependency>
                <groupId>org.junit.platform</groupId>
                <artifactId>junit-platform-surefire-provider</artifactId>
                <version>1.0.0-M1</version>
            </dependency>
        </dependencies>
    </plugin>
</plugins>
How to use
Following example of a functionality and its test:
public class FunWithStrings {
    public String getStringLength(final String string) {
        return string + ':' + string.length();
    }
}
public class FunWithStringsTest {
    private FunWithStrings cut = new FunWithStrings();
    // first, simple test
    @Test
    public void testGetStringLengthSimpleTest() {
        assertEquals("hello:5", cut.getStringLength("hello"), () -> "'hello' (length: 5) wasn't calculated properly");
    }
    @TestFactory
    public Stream<DynamicTest> createGetStringLengthTests() {
        final String[][] data = {
                // input, expected
                {"hello", "hello:5"},
                {"hel", "hel:3"},
                {"h", "h:1"},
                {"", ":0"},
                {" ", " :1"}
        };
        return Stream.of(data).map(o -> dynamicTest("test: " + o[0], () -> assertEquals(o[1], cut.getStringLength(o[0]))));
    }
    @Test
    public void testNull() {
        expectThrows(NullPointerException.class, () -> cut.getStringLength(null));
    }
}
The method annotated with @TestFactory is not a test itself but creates a stream of dynamic tests — in this usage similar to the idea of Parameterized tests of JUnit 4.
The following example shows how more sophisticated test scenarios could be realized. Imagine a system test scenario testing a resource which is available only after some startup time. The test should wait within a timeout for the resource being available.
Prior to JUnit 5 this could be realized with an @Rule.
@ExtendWith(MockedSystemExtension.class)
public class SystemTest {
    @Test
    public void test(final MockedSystem mockedSystem) {
        final Response response = mockedSystem.target().request().get();
        assertEquals(response.getStatusInfo().getFamily(), Response.Status.Family.SUCCESSFUL, () -> "status code is not 2xx");
        assertEquals(response.getHeaderString("X-Hello"), "World", () -> "header 'X-Hello' not correct");
    }
}
The MockedSystem can be injected in the test method due to the registered extension:
public class MockedSystemExtension implements ParameterResolver {
    @Override
    public boolean supports(final ParameterContext parameterContext, final ExtensionContext extensionContext) throws ParameterResolutionException {
        return parameterContext.getParameter().getType().isAssignableFrom(MockedSystem.class);
    }
    @Override
    public Object resolve(final ParameterContext parameterContext, final ExtensionContext extensionContext) throws ParameterResolutionException {
        final MockedSystem mockedSystem = new MockedSystem();
        waitForStartUp(mockedSystem);
        return mockedSystem;
    }
    private void waitForStartUp(MockedSystem mockedSystem) {
        // ...
    }
}
The system simulates a WebTarget which normally would be used to access an API.
Here I use Mockito to simulate a system which takes 10 seconds to start up.
public class MockedSystem {
    private static final int STARTUP_TIME = 10;
    private final WebTarget target;
    MockedSystem() {
        final WebTarget tut = mock(WebTarget.class);
        final Invocation.Builder builder = mock(Invocation.Builder.class);
        final Response notFoundResponse = mock(Response.class);
        final Response okResponse = mock(Response.class);
        final long start = System.currentTimeMillis();
        when(tut.request()).thenReturn(builder);
        when(builder.get()).then(a -> {
            if (System.currentTimeMillis() - start < STARTUP_TIME * 1000)
                return notFoundResponse;
            return okResponse;
        });
        when(notFoundResponse.getStatus()).thenReturn(404);
        when(notFoundResponse.getStatusInfo()).thenReturn(Response.Status.NOT_FOUND);
        when(okResponse.getStatus()).thenReturn(200);
        when(okResponse.getStatusInfo()).thenReturn(Response.Status.OK);
        when(okResponse.getHeaders()).thenReturn(new MultivaluedHashMap<>(Collections.singletonMap("X-Hello", "World")));
        when(okResponse.getHeaderString(anyString())).then(a -> ((Response) a.getMock()).getHeaders().getFirst(a.getArgument(0)));
        this.target = tut;
    }
    public WebTarget target() {
        return target;
    }
}
Therefore the SystemTest can rely that the injected MockedSystem was probed to be available before — transparent to the test class itself.
Further reading
These snippets are taken from my JUnit 5 Playground GitHub project.
Also see the JUnit 5 User Guide.
Happy testing!
Found the post useful? Subscribe to my newsletter for more free content, tips and tricks on IT & Java: