1. 概述

在本篇快速教程中,我们将展示 如何将 Mockito 与 JUnit 5 的扩展模型集成。如果你对 JUnit 5 的扩展机制还不太熟悉,可以先参考这篇 文章

我们会先介绍如何编写一个扩展,自动为类属性或方法参数上标注了 @Mock 注解的字段创建 Mock 对象。

然后,我们会在一个 JUnit 5 测试类中实际使用这个 Mockito 扩展。

2. Maven 依赖

首先,我们需要在 pom.xml 中添加 JUnit 5(即 jupiter)和 mockito 相关依赖:

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

此外,为了支持 JUnit 5 风格的 Mockito 扩展,还需要引入:

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

3. 构建测试类

接下来我们构建一个测试类,并通过 @ExtendWith 注解挂载 Mockito 扩展:

@ExtendWith(MockitoExtension.class)
class UserServiceUnitTest {

    UserService userService;

    // ...
}

我们可以使用 @Mock 注解来注入一个 Mock 实例变量,在整个测试类中都可以使用:

@Mock UserRepository userRepository;

也可以将 Mock 对象注入到方法参数中:

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

⚠️ 注意这里使用了 lenient() 方法。默认情况下,Mockito 会在初始化的 Mock 没有被任何一个测试方法调用时抛出 UnsupportedStubbingException。使用 lenient() 可以跳过这种严格的 Stub 校验。

我们甚至可以在单个测试方法的参数中注入 Mock 对象:

@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);
}

⚠️ 需要注意的是,作为测试方法参数注入的 MailClient Mock 实例,和 init 方法中注入的并不是同一个对象。

4. 小结

JUnit 5 提供了非常灵活且强大的扩展模型。我们展示了如何使用 Mockito 扩展来简化 Mock 对象的创建逻辑。

✅ 本文所有代码均可在我们的 GitHub 项目 中找到。


原始标题:Mockito and JUnit 5 - Using ExtendWith

« 上一篇: Apache Spark 入门指南
» 下一篇: JDO 查询入门