DEV Community

Cover image for Migrating from JUnit 4 to JUnit 5 with Spring Boot 2.3.x
Edgar Cirilo
Edgar Cirilo

Posted on

9 2

Migrating from JUnit 4 to JUnit 5 with Spring Boot 2.3.x

Recently, our team has moved to the last release of Spring (2.3.4). So we are taking advantage to move some projects unit tests to JUnit 5 due this is the default version since Spring Boot 2.2.x. Even though Junit 5 includes a vintage engine to support the JUnit 3 and JUnit 4 versions, we decided to fully migrate to JUnit Jupiter.

Dependencies

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-test</artifactId>
   <scope>test</scope>
   <exclusions>
    <exclusion>
     <groupId>org.junit.vintage</groupId>
     <artifactId>junit-vintage-engine</artifactId>
    </exclusion>
   </exclusions>
 </dependency>
Enter fullscreen mode Exit fullscreen mode

Annotations

In the new version of JUnit, the base package has changed to org.junit.jupiter.api and some annotations have changed. Below you will find a table with the mapping for the most used annotations.

JUnit 4 JUnit 5
org.junit.Test org.junit.jupiter.api.Test
org.junit.Before org.junit.jupiter.api.BeforeEach
org.junit.After org.junit.jupiter.api.AfterEach
org.junit.BeforeClass org.junit.jupiter.api.BeforeAll
org.junit.AfterClass org.junit.jupiter.api.AfterAll

Here is the API Documentation for the full list of annotations.

Exceptions

When using JUnit 4, we used the ExpectedException rule. However, it is no longer supported by JUnit 5. Fortunately, the Assertions API included in the Jupiter package have a handy way to assert the exceptions.

The assertThrows() method asserts that execution of the supplied executable throws an exception of the expectedType and returns the exception.

public static <T extends Throwable> T assertThrows(Class<T> expectedType, Executable executable)
Enter fullscreen mode Exit fullscreen mode

Once the exception is returned, we can use the preferred Assertions API. In our case, we use AssertJ, so it's pretty similar to any other object.

@Test
public void exampleMethod_ThrowsCustomException_Fail() {
  CustomException expectedException =
  Assertions.assertThrows(CustomException.class, () -> {
    service.doSomething(ObjectDTO dto);
  });
  assertThat(expectedException).isNotNull();
  assertThat(expectedException.getErrorCode()).isEqualTo(50);
}
Enter fullscreen mode Exit fullscreen mode

Spring

Spring provides some convenient annotations on behalf of JUnit 5.
@SpringJUnitConfig combines @ExtendWith(SpringExtension.class) and @ContextConfiguration into a single annotation. So, we have access to the configuration options through the @SpringJUnitConfig annotation.

@SpringJUnitConfig( classes = {TestConfig.class, SomeService.class}) 
public class SomeServiceTest {
    // class body...
}
Enter fullscreen mode Exit fullscreen mode

@SpringJUnitWebConfig is pretty similar, with the difference that it includes @WebAppConfiguration besides @ExtendWith(SpringExtension.class) and @ContextConfiguration

@SpringJUnitWebConfig( classes = {WebConfig.class, SomeController.class}) 
public class SomeControllerTest {

    @Autowired
    private WebApplicationContext webAppContext;
    // class body...
}
Enter fullscreen mode Exit fullscreen mode

You can read the official documentation of spring and spring boot to see the full list of annotations and a full description of each one.

Mockito

For Mockito, there are few changes to take into account. For previous versions, we used @RunWith but for JUnit 5 we have to use @ExtendWith instead:

@RunWith(MockitoJUnitRunner.class)
public class TheBestServiceTest {
    // class body...
}
Enter fullscreen mode Exit fullscreen mode

Is now

@ExtendWith(MockitoExtension.class)
public class TheBestServiceTest {
    // class body...
}
Enter fullscreen mode Exit fullscreen mode

Statics

Sometimes we need to mock some static methods. Usually, we use Powermock for this purpose. Nevertheless, Powermock won't be ported to the new version of JUnit. Fortunately, Mockito includes support for statics since the 3.4.x version.

In this case, we need to add some extra dependencies since spring-boot-starter-test only includes Mockito up to 3.3.3 version:

Dependencies

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-junit-jupiter</artifactId>
    <version>${mockito.version}</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-inline</artifactId>
    <version>${mockito.version}</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>${mockito.version}</version>
    <scope>test</scope>
</dependency>
Enter fullscreen mode Exit fullscreen mode

Usage

Now we can mock static methods! As a matter of fact, this works pretty much as the normal methods. Ee only need to use a generic class supplied by Mockito; MockedStatic<T>, and use it within a try clause:

try (MockedStatic<ClassWithStaticMethod> mockedStatic =  Mockito.mockStatic(ClassWithStaticMethod.class)) {
      mockedStatic.when(ClassWithStaticMethod::someStaticMethod).thenReturn(new SomeDTO());
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

I think JUnit 5 comes with a different approach than its past version, something quite interesting, which can help us improve our unit tests. Despite being a big change, JUnit 5 makes sure to have backward compatibility to make migration more manageable. However, I highly recommend taking that step whenever possible.

AWS Security LIVE!

Tune in for AWS Security LIVE!

Join AWS Security LIVE! for expert insights and actionable tips to protect your organization and keep security teams prepared.

Learn More

Top comments (0)

πŸ‘‹ Kindness is contagious

Discover a treasure trove of wisdom within this insightful piece, highly respected in the nurturing DEV Community enviroment. Developers, whether novice or expert, are encouraged to participate and add to our shared knowledge basin.

A simple "thank you" can illuminate someone's day. Express your appreciation in the comments section!

On DEV, sharing ideas smoothens our journey and strengthens our community ties. Learn something useful? Offering a quick thanks to the author is deeply appreciated.

Okay