You’ve heard of JUnit 5. It sounds pretty cool. So, maybe you want to move to JUnit 5, but you’re just not sure it’s all it will live up to the hype, right?
In this post, I’ll show you five of the best new features and capabilities of JUnit 5. When you’re done with this list, you’ll definitely want to make the move.
Feature #1 – Nested Unit Tests
Have you ever needed to group related JUnit tests together, and wrote a JUnit TestSuite to do it? Not because you really needed a test suite, really, but because that was the only way to do it? Were you wishing the whole time you could keep the tests in the same class? If so, the @Nested annotation will be welcome relief!
@Nested annotation feature of JUnit 5 lets you create cleaner unit test classes by using arbitrarily nested inner classes as additional units of test composition within a single test class. This allows you to keep the tests together, while at the same time allowing you to initialize them differently to simulate different runtime conditions.
Unit testing your code allows you to test all of the scenarios your code might encounter, but what good is that if you can’t make sense of the unit test reports? The ability to nest related test methods within the same test class, coupled with the new @DisplayName annotation, gives your unit tests a visual makeover. Your unit test reports never looked so good!
Feature #2 – JUnit Extensions
The JUnit 5 Extension Model follows the JUnit 5 team’s core principle of “Prefer extensions over features” and defines a number of extension points for which default implementations have been provided, but for which you may create Extensions to override the default behavior. These Extensions are callback interfaces that you implement and then register with the JUnit 5 framework, and when that extension point is reached when running a unit test, your code is invoked.
You might never need to write a custom extension, but the cool thing is, if you do, you use the same API that tool vendors use. In order to support JUnit, tool vendors often use its internal APIs, which limits what the JUnit maintainers can do in evolving the framework (it’s a catch-22). The Extension Model will allow JUnit to evolve by providing a consistent, public API for you, and tool vendors alike.
Plus, all public API methods are annotated with
@API and values like:
Experimental– the feature is new and the JUnit team welcomes feedback,
Internal– the feature is internal to JUnit and you and I should steer clear of using it, and
Maintained– the feature is good (will not be changed in a non-backward-compatible way) until at least the next minor release).
Extensions indeed! JUnit 5 is so flexible they should code name it JUnit Yoga. Seriously.
Feature #3 – Conditions
Speaking of Extensions, JUnit 5 provides two extension points –
TestExecutionCondition – that comprise the conditional test execution API. Oh, sure JUnit 4 let us @Ignore a test class or method, and JUnit 5 provides this behavior through the
But if you want, you can create your own custom extension of one of both of the conditional test execution API methods to inspect the currently running test and decide on-the-fly, whether or not to run a test class (via
ContainerExecutionCondition) or method (via
Wait, there’s more! JUnit 5 even allows you to deactivate conditions, like @Disabled (e.g., broken) unit tests, so you can do things like run them anyway to see if they’re still broken. Wow.
Feature #4 – Lambda Support
You love lambdas, right? I mean, who doesn’t? The ability to write compact code is very handy.
And now that feature is baked into JUnit 5 through the use of a few new
Executable. Methods like
Executable... as a varargs parameter for which you can substitute a lambda expression.
Other methods in
Supplier<String>, which let you use lambda expressions to provide messages, and BooleanSupplier to provide a boolean result, respectively.
Feature #5 – Parameterized Tests
Writing unit tests can get tedious, especially if you need to run the same unit test with different inputs. In this case, you pretty much have to write multiple unit test methods, or multiple blocks within a single method (which can leave a smell to your unit test). Have you ever wanted to make your unit tests a little more dynamic? What if you could setup a unit test method to run multiple times with different input values each time?
With parameterized tests, JUnit 5 allows you to specify one or more sources that supply your unit test method with the parameter values it needs to run its tests. The source generates the argument values that JUnit 5 then passes to your unit test method, one-at-a-time, until all argument values in the source are exhausted. Here are just a few examples of some of the out-of-the-box sources provided by JUnit 5:
- @ValueSource – lets you specify an array of primitive literals that will be passed one-at-a-time to the test method.
- @MethodSource – lets you specify one or more static, no-arg methods in the test class that returns a
Iterator, or array of argument values for your test method.
- @CsvSource – lets you specify a list of literals that are passed to the test method (broken into tuples based on the number of arguments in your test method).
- @ArgumentSource – lets you create your own custom arguments provider.
There are other cool features too, like:
- Parameter resolution, so you can pass parameters to unit test methods,
- Repeated tests, so you can run a test lots of times, and
- Dynamic tests, which actually let you write code to create unit tests on the fly!
If you are considering making the move to JUnit 5, I hope I’ve swayed you a little further. With cool features like this, why would you not make the switch?
Learn more about JUnit 5 and Java 9
- JUnit.org website