What’s new in JUnit 5.4

Java’s most popular testing library, JUnit, has released a new version. This version brings several welcome improvements since the last 5.3.2 release. In this blogpost I will go through the most important ones and give code examples where applicable.

As you might know, JUnit 5.x (Jupiter) is a huge improvement over JUnit 4.x (Vintage). JUnit 5 is a more modern version and includes features such as Lambda support, JUnit 5 extensions, test method parameter injection, and many more. JUnit 5.4 is an evolution of JUnit 5, and further improves the testing experience.

Getting started with JUnit 5.4

To get started with JUnit 5.4, we’re using Gradle. Using JUnit 5.4 has been simplified. While in the previous version of JUnit 5, it was necessary to include each module separately (for example, jupiter-api, jupiter-params, jupiter-engine), the new version allows you to using JUnit 5.4 by the inclusion of just the single junit-jupiter dependency-aggregating artifact.

Dependency inclusion in 5.3:

testCompile "org.junit.jupiter:junit-jupiter-api:5.3.0"
testCompile "org.junit.jupiter:junit-jupiter-params:5.3.0"
testRuntime "org.junit.jupiter:junit-jupiter-engine:5.3.0"

Can now be simplified in 5.4+ to:

testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter', version: '5.4.2'

To use JUnit 5 in your project, add the following line to your build.gradle file:

test {
    useJUnitPlatform()
}

@TempDir support for temporary directories

While testing, sometimes you need to get access to a temporarily file. Instead of handling the creation of such a file yourself, JUnit 5 now provides an extension to create and cleanup temporary files. You can use it putting the @TempDirectory annotation or Path or File test input parameters or fields. An example:

@Test
void useTempDir(@TempDir Path tempDir) throws IOException {
    Path file = tempDir.resolve("hello.txt");
    Files.write(file, "hello".getBytes());
    assertEquals(asList("hello"), Files.readAllLines(file));
}

Parameterized test null and empty support

Parameterized tests are a great way to to provide input to test methods. An example can be seen below:

@ParameterizedTest
@EnumSource(CountryCode.class)
void checkCountryCode(CountryCode countryCode) {
   assertTrue(countryChecker.isValid(countryCode));
}

In a setup like this it’s a bit harder to supply a null element or an empty element. @NullSource (and @EmptySource plus @NullAndEmptySource) to the rescue.

@ParameterizedTest
@NullSource // now also null is tested
@EnumSource(CountryCode.class)
void checkCountryCode(CountryCode countryCode) {
   assertTrue(countryChecker.isValid(countryCode));
}

Test display name is now smarter

Normally, when having test classes, it’s possible to override the test method name or class by using the @DisplayName annotation. For an example, see below.

@Test
@DisplayName("Apply 10% discount on products above $100")
public void applyDiscount() { }

While the above provides a more readable format, it’s quite static. What you can do instead is generate the display name based on the nested class or the method name. A good DisplayNameGeneration example can be found in the documentation.

How to order JUnit 5 test methods?

Generally it’s not a great idea to have test methods depend on each other. However, for some scenarios it’s handy to have a certain sequence in the test execution. For example, one test might create a resource in a REST endpoint. Subsequent tests can verify certain attributes of this resource.

In the previous versions of JUnit, this was hard to do, but since 5.4, you can use a new TestMethodOrder, named OrderAnnotation. You can use this annotation in combination with with the Order annotation to force the execution of the test methods in a specific order.

@TestMethodOrder(OrderAnnotation.class)
class SequenceTest {

    @Test
    @Order(1)
    void createResource() {
        // Create a resource first...
    }

    @Test
    @Order(2)
    void verify() {
        // ...then verify some attributes.
    }
}

What’s next?

There are many other features available in the new JUnit 5 release, which can be found in the release notes. One of the great things about JUnit 5, besides the framework, is that the documentation is of an amazing quality. There is a lot of documentation available, in which concepts are explained with very illustrative code examples.

If you haven’t already, it’s time to upgrade to JUnit 5. The latest release provides a lot of great features which will make migration worth it.

Older Post
Newer Post

Leave a Reply

Your email address will not be published. Required fields are marked *