In 2019, I gave a talk at Netcentric Summit about Junit5 migration and its advantages. You can check the content here:
- Video: Netcentric | JUnit 5, mockito 2 and AEM Mocks, is it true for you?
- Blog post: JUnit 5: leveraging new features for testing
After 3 years, I wanted to revisit the procedure to migrate from junit4 to junit5, so let’s do it! The result was this PR.
Steps
1. Dependencies
1.2 Main pom.xml
In the main pom.xml, replace
<dependencyManagement>
<dependencies>
...
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.xx</version>
<scope>test</scope>
</dependency>
...
</dependencies>
</dependencyManagement>
by (check the latest version in https://mvnrepository.com/artifact/org.junit/junit-bom)
<dependencyManagement>
<dependencies>
...
<!-- Junit bill of materials -->
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>5.8.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
...
</dependencies>
</dependencyManagement>
1.2 Module pom.xml
In the pom.xml of each module, replace
<dependencies>
...
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
...
</dependencies>
by
<dependencies>
...
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<!-- temporarily needed until the tests migration -->
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<scope>test</scope>
</dependency>
...
</dependencies>
2. Code Migration
I use Intellij to migrate the code.
- Go to Refactor > Migrate packages and classes > Junit (4.x -> 5.x)
- Try to compile your code to see if all import were correctly replaced
- If it compiles ok, you have the basic migration done. In most of the cases we need to rewrite some tests.
3. Upgrading the tests
3.1 @Test(expected=…)
Junit 5 has a more elegant way of testing expected exceptions. If you have
@Test(expected=IllegalArgumentException.class)
public void testIfExceptionIsThrown() throws Exception {
prepareMethod();
methodCall();
}
you need to migrate to
@Test
void testIfExceptionIsThrown() {
prepareMethod();
assertThrows(IllegalArgumentException.class, () -> methodCall());
}
3.2 @RunWith(MockitoJUnitRunner.class)
If you have
@RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
you need to migrate to the ExtendWith
and add a new dependency of Mockito.
Check the latest version at https://mvnrepository.com/artifact/org.mockito/mockito-junit-jupiter.
New dependency:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>4.6.1</version>
<scope>test</scope>
</dependency>
And then the new ExtendWith:
@ExtendWith(MockitoExtension.class)
public class MyClassTest {
3.3 Replace imports
Sometimes the migration fails to replace all imports. Do it manually
Old import | New import |
---|---|
import static org.mockito.Matchers.any; | import static org.mockito.ArgumentMatchers.any; |
import static org.junit.Assert. | import static org.junit.jupiter.api.Assertions. |
3.4 Unnecessary stubbings detected.
New Mockito versions are more strict about unnecessary stubbing and they want you to use strict stubbing. If you do not want to touch your tests yet to make them more strict, you will need to add another annotation to your class or add lenient to your mock.
Class configuration
Add @MockitoSettings(strictness = Strictness.LENIENT)
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
public class MyClassTest {
Test configuration
Add lenient()
in front of each failed stubbing:
lenient().when(mock.getName()).thenReturn(name);
3.5 Parametrized tests
In Junit5 the parametrized tests were redesigned. Take a look on Parameterized Tests section.
References
- Migrating from JUnit 4 to JUnit 5 | The IntelliJ IDEA Blog
- Mockito and JUnit 5 - Using ExtendWith | Baeldung
If you found any error or want to help me to improve this article, please comment the pull request.