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.
原文链接:Migrating from JUnit 4 to JUnit 5 with Spring Boot 2.3.x
暂无评论内容