Mockito and JUnit 5 – Using ExtendWith – Mockito和JUnit 5 – Using ExtendWith

最后修改: 2017年 10月 29日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this quick tutorial, 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.

在这个快速教程中,我们将展示如何将Mockito与JUnit 5扩展模型集成。要了解有关JUnit 5扩展模型的更多信息,请看此文章

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

首先,我们将展示如何创建一个扩展,为任何用@Mock注释的类属性或方法参数自动创建模拟对象。

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

然后我们将在JUnit 5的测试类中使用我们的Mockito扩展。

2. Maven Dependencies

2.Maven的依赖性

2.1. Required Dependencies

2.1.必要的依赖性

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

让我们把JUnit 5 (jupiter)和mockito的依赖性添加到我们的pom.xml中。

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

2.2. Surefire Plugin

2.2.万无一失的插件

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

让我们也配置一下Maven Surefire插件,使用新的JUnit平台启动器运行我们的测试类。

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

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

junit-jupiter-enginemockito-corejunit-platform-surefire-provider的最新版本可以从Maven中心下载。

3. Mockito Extension

3.Mockito扩展

Mockito provides an implementation for JUnit5 extensions in the library – mockito-junit-jupiter.

Mockito在库中为JUnit5扩展提供了一个实现–mockito-junit-jupiter

We’ll include this dependency in our pom.xml:

我们将在我们的pom.xml中包括这一依赖关系。

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

4. Building the Test Class

4.构建测试类

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

让我们建立我们的测试类,并将Mockito扩展附加到它。

@ExtendWith(MockitoExtension.class)
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注解来为一个实例变量注入一个模拟,我们可以在测试类的任何地方使用。

@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 initialized mock is not called by one of the test methods during execution. We can avoid this strict stub checking by using this method when initializing the mocks.

请注意这里使用的是Mockito.lenient()Mockito在执行过程中,如果一个初始化的mock没有被某个测试方法调用,就会抛出一个UnsupportedStubbingException。我们可以通过在初始化mock的时候使用这个方法来避免这种严格的存根检查。

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);
    assertNotNull(user.getId());
    verify(mailClient).sendUserRegistrationMail(insertedUser);
}

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

请注意,我们作为测试参数注入的MailClient模拟将不是我们在init方法中注入的同一个实例。

5. Conclusion

5.结论

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

Junit 5为扩展提供了一个不错的模型。我们演示了一个简单的Mockito扩展,简化了我们的模拟创建逻辑。

All the code used in this article can be found on our GitHub project.

本文中使用的所有代码都可以在我们的GitHub项目中找到。