Table of contents
1.
Introduction
2.
Advantages of JUnit5
3.
Difference between JUnit4 and JUnit5
3.1.
Annotations
3.1.1.
JUnit4
3.1.2.
JUnit5
3.2.
Assertions
3.2.1.
JUnit4
3.2.2.
JUnit5
3.3.
Assumptions
3.4.
Tagging & Filtering
3.5.
New Annotations for a Test run
3.5.1.
JUnit4
3.5.2.
JUnit5
3.6.
New Test rule Annotations
3.6.1.
JUnit4
3.7.
JUnit5 Vintage
4.
FAQs
5.
Key Takeaways
Last Updated: Mar 27, 2024

Migrating from JUnit4 to JUnit5

Author Aman Thakur
0 upvote
Career growth poll
Do you think IIT Guwahati certified course can help you in your career?

Introduction

Due to technical debt, the majority of businesses are having difficulty implementing digital changes. One of them is unit testing. JUnit is one of the unit testing frameworks. Unit tests were generally written with JUnit version 4 in the industry. Although JUnit 5 has been in the market for some time, the migration of JUnit 5 has slowed. The lack of a defined migration path for developers is the reason behind this.

This article covers how to migrate from JUnit 4 to JUnit 5 from start to finish. It covers backward compatibility using JUnit Vintage.It covers Annotation, Assertions and Assumption in JUnit5. Let’s get started with our migration to JUnit5 from JUnit4 journey.

Advantages of JUnit5

JUnit4 has some clear limitations which are resolved in the later build of JUnit5 listed below

  1. A single jar library included the complete framework. Even if only a single feature is required, the entire library must be imported. We have more granularity in JUnit 5 and can import only what we need.
  2. JUnit 4 tests can only be run by one test runner at a time (e.g. SpringJUnit4ClassRunner or Parameterized ). JUnit 5 allows many runners to run at the same time.
  3. JUnit 4 never progressed past Java 7, hence it missed out on a number of Java 8 features. JUnit 5 makes extensive use of Java 8 capabilities.
    The idea behind was to rewrite JUnit to solve most of its drawbacks.

Difference between JUnit4 and JUnit5

JUnit4 was divided into two modules that comprise JUnit5

1. JUnit Platform: This module covers all possible extension frameworks for test execution, discovery, and reporting.


2. JUnit Vintage: Backward compatibility with JUnit 4 and even JUnit 3 is possible with this module.

Annotations

Annotations in JUnit 5 have undergone significant modifications. The most significant change is that we can no longer declare expectations using the @Test annotation.

JUnit4

@Test(expected = Exception.class)
public void shouldRaiseAnException() throws Exception {
    // ...
}
You can also try this code with Online Java Compiler
Run Code
@Test(timeout = 1)
public void shouldFailBecauseTimeout() throws InterruptedException {
    Thread.sleep(10);
}
You can also try this code with Online Java Compiler
Run Code

JUnit5

public void shouldRaiseAnException() throws Exception {
    Assertions.assertThrows(Exception.class, () -> {
        //...
    });
}
You can also try this code with Online Java Compiler
Run Code
@Test
public void shouldFailBecauseTimeout() throws InterruptedException {
    Assertions.assertTimeout(Duration.ofMillis(1), () -> Thread.sleep(10));
}
You can also try this code with Online Java Compiler
Run Code

Other Annotation which are changed in JUnit5 are as follows:

  • @Before -> @BeforeEach
  • @After -> @AfterEach
  • @BeforeClass -> @BeforeAll
  • @AfterClass -> @AfterAll
  • @Ignore -> @Disable 

Assertions

In JUnit 5, we may now create assertion messages in lambdas, allowing lazy evaluation to forgo complicated message generation unless it's absolutely necessary:

JUnit4

@Test
public void shouldFailBecauseTheNumbersAreNotEqual_lazyEvaluation() {
    Assertions.assertTrue(
      2 == 3, 
      () -> "Numbers " + 2 + " and " + 3 + " are not equal!");
}
You can also try this code with Online Java Compiler
Run Code

JUnit5

Test Program

@Test
public void incrementalArray() {
   List<Integer> list = Arrays.asList(10, 20, 30);
   Assertions.assertAll("Check if the array is incremental",
           () -> Assertions.assertEquals(list.get(0).intValue(), 10),
           () -> Assertions.assertEquals(list.get(1).intValue(), 20),
           () -> Assertions.assertEquals(list.get(2).intValue(), 30));
}
You can also try this code with Online Java Compiler
Run Code

Assumptions

The new org.JUnit.jupiter.api contains Assumption class It not only support the assumption of JUnit4 but also add new features to JUnit5.

@Test
public void whenEnvironmentIsWeb_thenUrlsShouldStartWithHttp() {
    assumingThat("WEB".equals(System.getenv("ENV")),
      () -> {
          assertTrue("http".startsWith(address));
      });
}
You can also try this code with Online Java Compiler
Run Code

Tagging & Filtering

We may use the @Category annotation in JUnit 4 to categorise tests. The @Category annotation has been superseded with the @Tag annotation in JUnit 5

@Tag("annotations")
@Tag("JUnit5")
@RunWith(JUnitPlatform.class)
public class AnnotationTestExampleTest {
    /*...*/
}
You can also try this code with Online Java Compiler
Run Code

We can include/exclude particular tags using the maven-surefire-plugin:

<build>
    <plugins>
        <plugin>
            <artifactId>maven-surefire-plugin</artifactId>
            <configuration>
                <properties>
                    <includeTags>JUnit5</includeTags>
                </properties>
            </configuration>
        </plugin>
    </plugins>
</build>

New Annotations for a Test run

In JUnit 4, the @RunWith annotation was used to connect the test environment with other frameworks or to modify the overall execution flow in test cases.

We can now utilise the @ExtendWith annotation with JUnit 5 to offer comparable functionality.

JUnit4

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
  {"/app-config.xml", "/test-data-access-config.xml"})
public class SpringExtensionTest {
    /*...*/
}
You can also try this code with Online Java Compiler
Run Code

JUnit5

@ExtendWith(SpringExtension.class)
@ContextConfiguration(
  { "/app-config.xml", "/test-data-access-config.xml" })
public class SpringExtensionTest {
    /*...*/
}
You can also try this code with Online Java Compiler
Run Code

New Test rule Annotations

The @Rule and @ClassRule annotations in JUnit 4 were used to add additional functionality to tests. The @ExtendWith annotation in JUnit 5 may be used to replicate the same logic.

JUnit4

public class TraceUnitTestRule implements TestRule {

    @Override
    public Statement apply(Statement base, Description description) {
        return new Statement() {
            @Override
            public void evaluate() throws Throwable {
                // Before and after an evaluation tracing here 
                ...
            }
        };
    }
}
You can also try this code with Online Java Compiler
Run Code

And we implement the test suit as follows:

@Rule
public TraceUnitTestRule traceRuleTests = new TraceUnitTestRule();
JUnit5
public class TraceUnitExtension implements AfterEachCallback, BeforeEachCallback{

    @Override
    public void beforeEach(TestExtensionContext context) throws Exception{
        // ...
    }

    @Override
    public void afterEach(TestExtensionContext context) throws Exception{
        // ...
    }
}
You can also try this code with Online Java Compiler
Run Code

We can simply implement this rule in the test suite using JUnit 5's AfterEachCallback and BeforeEachCallback interfaces, which are available in the package org.JUnit.jupiter.api.extension:

@RunWith(JUnitPlatform.class)
@ExtendWith(TraceUnitExtension.class)
public class RuleExampleTest {
 
    @Test
    public void whenTracingTests() {
        /*...*/
    }
}
You can also try this code with Online Java Compiler
Run Code

JUnit5 Vintage

JUnit Vintage facilitates JUnit test migration by executing JUnit 3 or JUnit 4 tests in a JUnit 5 context. We may utilise it by adding the JUnit Vintage Engine to our project:

<dependency>
    <groupId>org.JUnit.vintage</groupId>
    <artifactId>JUnit-vintage-engine</artifactId>
    <version>${JUnit5.vintage.version}</version>
    <scope>test</scope>
</dependency>

FAQs

  1. Is JUnit5 better than JUnit4?
    Migrating tests from JUnit 4 to JUnit 5 may seem onerous if you've been using it for a long time. JUnit 5 takes advantage of technologies introduced in Java 8 or later, such as lambda functions, to make tests more powerful and maintainable.
     
  2. Does Spring boot use JUnit4 or JUnit5?
    Spring Boot's spring-boot-starter-test requirement imports the JUnit 4 dependencies by default. To utilise JUnit 5, we must remove JUnit 4 from the project dependencies and replace it with JUnit 5. We're utilising the most recent version of Spring Boot, which is 2.1.7.
     
  3. Is TestNG better than JUnit?
    TestNG has the ability to arrange test methods into Java groups. It runs unit tests using arguments passed into the test functions. The usage of Threads improves testing performance by reducing execution time. JUnit's issue of not being able to run concurrent tests has been overcome.
     
  4. In JUnit5, which of the following annotations is used to rerun a test several times?
    For a test function, instead of using the annotation @Test, the annotation @RepeatedTest is used. The input parameter of the annotation is set to a number. The execution is then performed as many times as the selected test method allows.

Key Takeaways

If you have reached till here that means you get significant idea  how to migrate a JUnit 4 project to a new JUnit 5 version in this exercise. In JUnit 5, you learned how to maintain backward compatibility with JUnit 4.

Hope you wish to learn more about articles such as implementation of nested test in JUnit Hence never stop your quest to learning.

Happy Learning!

Live masterclass