Mockito和JUnit 5 –使用ExtendWith

Mockito and JUnit 5 – Using ExtendWith

1.简介

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

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

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

2. Maven依赖

2.1。必需的依存关系

让我们向我们的pom.xml中添加JUnit 5(木星)和ockockito依赖项:

1
2
3
4
5
6
7
8
9
10
11
12
<dependency>
    <groupId>org.junit.jupiter</groupId>
    junit-jupiter-engine</artifactId>
    <version>5.3.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    mockito-core</artifactId>
    <version>2.21.0</version>
    <scope>test</scope>
</dependency>

请注意,junit-jupiter-engine是主要的JUnit 5库,junit-platform-launcheris与Maven插件和IDE启动器一起使用。

2.2。 Surefire插件

让我们还配置Maven Surefire插件,以使用新的JUnit平台启动器运行测试类:

1
2
3
4
5
6
7
8
9
10
11
<plugin>
    maven-surefire-plugin</artifactId>
    <version>2.19.1</version>
    <dependencies>
        <dependency>
             <groupId>org.junit.platform</groupId>
             junit-platform-surefire-provider</artifactId>
             <version>1.0.1</version>
         </dependency>
     </dependencies>
</plugin>

2.3。 JUnit 4 IDE兼容性依赖性

为了使我们的测试用例与JUnit4(老式)兼容,对于尚不支持JUnit 5的IDE,让我们包括以下依赖项:

1
2
3
4
5
6
7
8
9
10
11
12
<dependency>
    <groupId>org.junit.platform</groupId>
    junit-platform-runner</artifactId>
    <version>1.2.0</version>
    <scope>test</scope>
</dependency>
<dependency>
     <groupId>org.junit.vintage</groupId>
     junit-vintage-engine</artifactId>
     <version>5.2.0</version>
     <scope>test</scope>
</dependency>

另外,我们应该考虑使用@RunWith(JUnitPlatform.class)注释所有测试类。

可以从Maven Central下载Junit-Jupiter-engine,junit-vintage-engine,junit-platform-launcher和mockito-core的最新版本。

3. Mockito扩展

Mockito为库中的JUnit5扩展提供了一个实现– mockito-junit-jupiter。我们将这种依赖关系包含在pom.xml中:

1
2
3
4
5
6
<dependency>
    <groupId>org.mockito</groupId>
    mockito-junit-jupiter</artifactId>
    <version>2.23.0</version>
    <scope>test</scope>
</dependency>

4.建立测试类

让我们构建测试类并将Mockito扩展附加到它:

1
2
3
4
5
6
7
8
@ExtendWith(MockitoExtension.class)
@RunWith(JUnitPlatform.class)
public class UserServiceUnitTest {

    UserService userService;

... //
}

我们可以使用@Mockannotation为可在测试类中任何地方使用的实例变量注入模拟:

1
@Mock UserRepository userRepository;

另外,我们可以将模拟对象注入到方法参数中:

1
2
3
4
5
6
7
8
9
10
@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);
}

请注意此处使用Mockito.lenient()。当执行期间测试方法之一未调用初始化的模拟时,Mockito会引发UnsupportedStubbingException。通过在初始化模拟时使用此方法,可以避免进行严格的存根检查。

我们甚至可以将模拟对象注入测试方法参数中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@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);
}

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

5.结论

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

可以在GitHub项目的com.baeldung.junit5.mockito软件包中找到本文中使用的所有代码,以及一些其他的单元测试方法。