'Y'

Migrating from JUnit 4 to JUnit 5: replacing rules with the extension model. Part 1

JUnit 5 Jupiter is the combination of the new programming model (annotations, classes, methods) and extension model for writing tests and extensions in JUnit 5. The Jupiter sub-project provides a test engine for running Jupiter based tests on the platform. In contrast to the previously existing runners and rules extension points in JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the Extension API.

JUnit 5 Jupiter is the combination of the new programming model (annotations, classes, methods) and extension model for writing tests and extensions in JUnit 5. The Jupiter sub-project provides a test engine for running Jupiter based tests on the platform. In contrast to the previously existing runners and rules extension points in JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the Extension API.

Rules vs. the extension model


A JUnit 4 rule is a component that intercepts test method calls and allows you to do something before a test method is run and something else after a test method has been run. They are specific to JUnit 4.

In some sense, a rule is similar to having the JUnit 4 @Before and @After annotations in our test class. But, by using a rule, we can have everything isolated in one place and reuse the code easily from multiple test classes.

To add behavior to the executed tests, you must use the @Rule annotation on TestRule fields. This increases the flexibility of the tests by creating objects that can be used and configured into the test methods.


Testing exceptions

In order to put face-to-face the rules model of JUnit 4 and the extension model of JUnit 5, lets use a Calculator class (listing 1). Its used to execute mathematical operations. We are interested in testing the methods that may throw exceptions. One JUnit 4 rule is ExpectedException and well show how it can be replaced by the JUnit 5 assertThrows method.


Listing 1 The Calculator class

The Calculator class.PNG

The logic that may throw exceptions into the Calculator class does the following:

  1. Declares a method to calculate the square root of a number (1). In case the number is negative, an exception containing a particular message is created and thrown (2).
  2. Declares a method to divide two numbers (3). In case the second number is zero, an exception containing a particular message is created and thrown (4).

Listing 2 provides an example that specifies which exception message is expected during the execution of the test code using the new functionality of the Calculator class above.


Listing 2 The JUnit4RuleExceptionTester class

JUnit4RuleExceptionTester class.PNG

Into the previous JUnit 4 example, we do the following:

  1. We declare an ExpectedException field annotated with @Rule. The @Rule annotation must be applied either on a public non-static field or on a public non-static method (1). The ExpectedException.none() factory method creates an unconfigured ExpectedException.
  2. We initialize an instance of the Calculator class whose functionality we are testing (2).
  3. The ExpectedException is configured to keep the type of exception (3) and the message (4), before being thrown by invoking the sqrt method at line (5).
  4. The ExpectedException is configured to keep the type of exception (6) and the message (7), before being thrown by invoking the divide method at line (8).

Now, we move our attention to the new JUnit 5 approach.

Interested in JUnit? Check out our trainings.


Catalin Tudose
Java and Web Technologies Expert

Share the knowledge

Still have questions?
Connect with us
Thank you.
Your request has been received.