Five JUnit 5 Features You Might Not Know Yet

Last Updated:  July 22, 2024 | Published: July 12, 2020

Writing your first test with JUnit 5 is straightforward. Annotate your test method with @Test and verify the result using assertions. Apart from the basic testing functionality of JUnit 5, there are some features you might not have heard about (yet). Discover five JUnit 5 features I found useful while working with JUnit 5: test execution order, nesting tests, parameter injection, parallelizing tests, and conditionally run tests.

Test Execution Ordering

The first feature we'll explore is influencing the test execution order.

While JUnit 5 has the following default-test execution order:

…, test methods will be ordered using an algorithm that is deterministic but intentionally nonobvious. This ensures that subsequent runs of a test suite execute test methods in the same order, thereby allowing for repeatable builds.

you can configure a different ordering mechanism.

Therefore, either implement your own MethodOrderer or use a built-in that orders: alphabetically, randomly, or numerically based on a specified value.

Let's take a look at how to order some unit tests using the OrderAnnotation ordering mechanism:

With @TestMethodOrder(MethodOrderer.OrderAnnotation.class) you basically opt-out from the JUnit 5 default ordering. The actual order is then specified with @Order. A lower value implies a higher priority.

Once you execute the tests above, the order is the following: testOne, testTwo and testThree.

As a general best practice your test should not rely on the order they are executed. Nevertheless, there are scenarios where this feature helps to execute the tests in configurable order.

Nesting Tests With JUnit 5

Usually, you test different business requirements inside the same test class. With Java and JUnit 5, you write them one after the other and add new tests to the bottom of the class.

While this is working for a small number of tests inside a class, this approach gets harder to manage for bigger test suites. Consider you want to adjust tests that verify a common scenario. As there is no defined order or grouping inside your test class you end up scrolling and searching them.

The following JUnit 5 feature allows you to counteract this pain point of a growing test suite: nested tests.

You can use this feature to group tests that verify common functionality. This does not only improves maintainability but also reduces the time to understand what the class under test is responsible for:

You might run into issues while using this feature in conjunction with some Spring Boot test features.

Parameter Injection With JUnit 5

JUnit 5 offers parameter injection for test constructor and method arguments. There are built-in parameter resolvers you can use to inject an instance of TestReport, TestInfo, or RepetitionInfo (in combination with a repeated test):

Furthermore, you can implement your own ParameterResolver to resolve arguments of any type.

We can use this mechanism to resolve a random UUID for our tests:

With supportsParameter we indicate that this resolver is capable of resolving a requested parameter, as you can have multiple ParameterResolver . We're checking if the requested parameter is annotated with our custom annotation. In addition, you could also verify that the parameter is of type String.

We can use this resolver for our tests once we register this extension with @ExtendWith:

Test Parallelization With JUnit 5

While you might have configured this in the past with the corresponding Maven or Gradle plugin, you can now configure this as an experimental feature with JUnit (since version 5.3). This gives you more fine-grain control on how to parallelize the tests.

A basic configuration can look like the following:

This enables parallel execution for all your tests and set the execution mode to concurrent. Compared to same_threadconcurrent does not enforce to execute the test in the same thread of the parent. For a per test class or method mode configuration, you can use the @Execution annotation.

There are multiple ways to set these configuration values, one is to use the Maven Surefire plugin for it:

or a junit-platform.properties file inside src/test/resources with the configuration values as content.

You should benefit the most when using this feature for unit tests. Enabling parallelization for integration tests might not be possible or easy to achieve, depending on your setup. Therefore, I can recommend executing your unit tests with the Maven Surefire plugin and configuring parallelization for them. All your integration tests can then be executed with the Maven Failsafe plugin, where you don't specify these JUnit 5 configuration parameters.

For more fine-grain parallelism configuration, take a look at the official JUnit 5 documentation.

Conditionally Disable Tests with JUnit 5

The last feature is useful when you want to avoid tests being executed based on different conditions. There might be tests that don't run on different operating systems or require different environment variables to be present.

JUnit 5 comes with some built-in conditions that you can use for your tests, e.g.:

On the other side, writing a custom condition is pretty straightforward. Let's consider you don't want to execute a test around midnight:

All you have to do is to implement ExecutionCondition and add your own condition:

There is a dedicated testing category available on my blog for more content about JUnit and topics like Testcontainers, testing Spring Boot or Jakarta EE applications, etc.

You can find the source code for these five JUnit 5 features on GitHub.

Have fun using these JUnit 5 features,

Philip

>