Mockito and JUnit 5 – Using ExtendWith

1. Introduction

In this quick article, we’ll show how to integrate Mockito with the JUnit 5 extension model. To learn more about the JUnit 5 extension model, have a look at this article.

First, we’ll show how to create an extension that automatically creates mock objects for any class attribute or method parameter annotated with @Mock.

Then, we’ll use our Mockito extension in a JUnit 5 test class.

2. Maven Dependencies

2.1. Required Dependencies

Let’s add the JUnit 5 (jupiter) and mockito dependencies to our pom.xml:

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-engine</artifactId>
    <version>5.3.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>2.21.0</version>
    <scope>test</scope>
</dependency>

Note that junit-jupiter-engine is the main JUnit 5 library, and junit-platform-launcher is used with the Maven plugin and IDE launcher.

2.2. Surefire Plugin

Let’s also configure the Maven Surefire plugin to run our test classes using the new JUnit platform launcher:

<plugin>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.19.1</version>
    <dependencies>
        <dependency>
             <groupId>org.junit.platform</groupId>
             <artifactId>junit-platform-surefire-provider</artifactId>
             <version>1.0.1</version>
         </dependency>
     </dependencies>
</plugin>

2.3. JUnit 4 IDE Compatibility Dependencies

For our test cases to be JUnit4 (vintage) compatible, for IDEs that have no support for JUnit 5 yet, let’s include these dependencies:

<dependency>
    <groupId>org.junit.platform</groupId>
    <artifactId>junit-platform-runner</artifactId>
    <version>1.2.0</version>
    <scope>test</scope>
</dependency>
<dependency>
     <groupId>org.junit.vintage</groupId>
     <artifactId>junit-vintage-engine</artifactId>
     <version>5.2.0</version>
     <scope>test</scope>
</dependency>

Also, we should consider annotating all our test classes with @RunWith(JUnitPlatform.class)

The latest versions of junit-jupiter-engine, junit-vintage-engine, junit-platform-launcher, and mockito-core can be downloaded from Maven Central.

3. Mockito Extension

Mockito provides an implementation for JUnit5 extensions in the library – mockito-junit-jupiter. We’ll include this dependency in our pom.xml:

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-junit-jupiter</artifactId>
    <version>2.23.0</version>
    <scope>test</scope>
</dependency>

4. Building the Test Class

Let’s build our test class and attach the Mockito extension to it:

@ExtendWith(MockitoExtension.class)
@RunWith(JUnitPlatform.class)
public class UserServiceUnitTest {

    UserService userService;

... //
}

We can use the @Mock annotation to inject a mock for an instance variable that we can use anywhere in the test class:

@Mock UserRepository userRepository;

Also, we can inject mock objects into method parameters:

@BeforeEach
void init(@Mock SettingRepository settingRepository) {
    userService = new DefaultUserService(userRepository, settingRepository, mailClient);
      
    Mockito.lenient().when(settingRepository.getUserMinAge()).thenReturn(10);
        
    when(settingRepository.getUserNameMinLength()).thenReturn(4);
        
    Mockito.lenient()
        .when(userRepository.isUsernameAlreadyExists(any(String.class)))
            .thenReturn(false);
}

Please note the use of Mockito.lenient() here. Mockito throws an UnsupportedStubbingException, when an initialised mock is not called by one of the test methods during execution. We can avoid this strict stub checking by using this method when initialising the mocks.

We can even inject a mock object into a test method parameter:

@Test
void givenValidUser_whenSaveUser_thenSucceed(@Mock MailClient mailClient) {
    // Given
    user = new User("Jerry", 12);
    when(userRepository.insert(any(User.class))).then(new Answer<User>() {
        int sequence = 1;
            
        @Override
        public User answer(InvocationOnMock invocation) throws Throwable {
            User user = (User) invocation.getArgument(0);
            user.setId(sequence++);
            return user;
        }
    });

    userService = new DefaultUserService(userRepository, settingRepository, mailClient);

    // When
    User insertedUser = userService.register(user);
        
    // Then
    verify(userRepository).insert(user);
    Assertions.assertNotNull(user.getId());
    verify(mailClient).sendUserRegistrationMail(insertedUser);
}

Note that the MailClient mock that we inject as a test parameter will NOT be the same instance that we injected in the init method.

5. Conclusion

Junit 5 has provided a nice model for extension. We demonstrated a simple Mockito extension that simplified our mock creation logic.

All the code used in this article can be found in the com.maixuanviet.junit5.mockito package of the GitHub project, along with a few additional unit test methods.

Related posts:

Java Program to Represent Graph Using Linked List
Testing in Spring Boot
Using Custom Banners in Spring Boot
Hướng dẫn sử dụng luồng vào ra ký tự trong Java
The Dining Philosophers Problem in Java
Java Program to Find Nearest Neighbor for Dynamic Data Set
Java Program to Check for balanced parenthesis by using Stacks
Đồng bộ hóa các luồng trong Java
Finding the Differences Between Two Lists in Java
Java Program to Check if an UnDirected Graph is a Tree or Not Using DFS
Hướng dẫn Java Design Pattern – Bridge
Một số từ khóa trong Java
Using Spring @ResponseStatus to Set HTTP Status Code
Remove the First Element from a List
REST Web service: HTTP Status Code và xử lý ngoại lệ RESTful web service với Jersey 2.x
Spring Data Reactive Repositories with MongoDB
Java Program to Construct an Expression Tree for an Infix Expression
Using the Not Operator in If Conditions in Java
Từ khóa static và final trong java
Generic Constructors in Java
Thực thi nhiều tác vụ cùng lúc như thế nào trong Java?
Java Program to Implement vector
Spring Boot Configuration with Jasypt
Vòng lặp for, while, do-while trong Java
Intro to Inversion of Control and Dependency Injection with Spring
Spring @RequestMapping New Shortcut Annotations
Convert Hex to ASCII in Java
Java Program to Perform String Matching Using String Library
Spring Boot - Actuator
HttpAsyncClient Tutorial
Java Program to Implement Park-Miller Random Number Generation Algorithm
Spring Boot Application as a Service