Migrating from JUnit 4 to JUnit 5: implementing the migration, dependencies, annotations. Part 3
4. Effective migration
We start the demonstration with a class that simulates a system under test (SUT). This class can be initialized, can receive regular work but cannot receive additional work to execute, and can close itself.
Listing 4 Tested SUT class
Listing 5 verifies the functionality of the SUT by using the JUnit 4 facilities, and listing 6 verifies the functionality of the SUT by using the JUnit 5 facilities. These examples also demonstrate the life cycle methods. As previously stated, the system can start up, receive regular and additional work, and close itself. The JUnit 4 and JUnit 5 life cycle and testing methods ensure that the system is initializing and then shutting down before and after each effective test. The test methods check whether the system can receive regular work and additional work.
Listing 5 JUnit4SUTTest class
We previously replaced the JUnit 4 dependency with the JUnit Vintage dependency. The result of running the JUnit4SUTTest class is the same in both cases (figure 2), and mySecondTest is marked with the @Ignore annotation. Now we can proceed to the effective migration of annotations, classes, and methods.
Fig. 2 Running the JUnit4SUTTestSuite in IntelliJ using both the JUnit 4 dependency and the JUnit Vintage dependency
Listing 6 JUnit5SUTTest class
Comparing the JUnit 4 and JUnit 5 methods, we see that
- The methods annotated with @BeforeClass (#1 in listing 5) and @BeforeAll (#1 in listing 6), respectively, are executed once, before all tests. These methods need to be static. In the JUnit 4 version, the methods also need to be public. In the JUnit 5 version, we can make the methods nonstatic and annotate the whole test class with @TestInstance(Life cycle.PER_CLASS).
- The methods annotated with @AfterClass (#2 in listing 5) and @AfterAll (#2′ in listing 6), respectively, are executed once, after all tests. These methods need to be static. In the JUnit 4 version, the methods also need to be public. In the JUnit 5 version, we can make the methods nonstatic and annotate the whole test class with @TestInstance(Life cycle.PER_CLASS).
- The methods annotated with @Before (#3 in listing 5) and @BeforeEach (#3′ in listing 6), respectively, are executed before each test. In the JUnit 4 version, the methods need to be public.
- The methods annotated with @After (#4 in listing 5) and @AfterEach (#4′ in listing 6), respectively, are executed after each test. In the JUnit 4 version, the methods need to be public.
- The methods annotated with @Test (#5 in listing 5) and @Test (#5′ in listing 6) are executed independently. In the JUnit 4 version, the methods need to be public. The two annotations belong to different packages: org.junit.Test and org.junit.jupiter.api.Test, respectively.
- To skip the execution of a test method, JUnit 4 uses the annotation @Ignore (#6 in listing 5), whereas JUnit 5 uses the annotation @Disabled (#6′ in listing 6).
The access level has been relaxed for the test methods, from public to package-private. These methods are accessed only from within the package to which the test class belongs to, so they didn’t need to be made public.
Conclusions
This article has demonstrated the steps needed by the migration from JUnit 4 to JUnit 5 and summarizing them into a guiding table: replace the dependencies, replace the annotations, replace the testing classes and methods. JUnit 4 is and will still be in use, because there is a large amount of already written tests. You may consider slowly migrating your code to the new JUnit 5 approach.