将Mockito Mock注入Spring Beans

2023/05/12

1. 概述

在本教程中,我们介绍如何使用依赖注入将Mockito mock注入Spring Beans以进行单元测试。

在实际应用程序中,组件通常依赖于访问外部系统,因此提供适当的测试隔离非常重要,这样我们就可以专注于测试给定单元的功能,而不必涉及每个测试的整个类层次结构。注入mock是引入这种隔离的一种很好的方法。

2. Maven依赖

我们需要以下Maven依赖项来进行单元测试和mock对象:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
    <version>2.6.1</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <version>2.6.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>4.0.0</version>
</dependency>

我们在这个例子中使用Spring Boot,但原生的Spring框架也可以正常配置Mockito使用。

3. 编写测试

3.1 业务逻辑

首先,让我们创建一个我们将要测试的简单Service类:

@Service
public class NameService {
    
    public String getUserName(String id) {
        return "Real user name";
    }
}

然后我们将它注入到UserService类中:

@Service
public class UserService {

    private final NameService nameService;

    @Autowired
    public UserService(NameService nameService) {
        this.nameService = nameService;
    }

    public String getUserName(String id) {
        return nameService.getUserName(id);
    }
}

为了简单起见,不论提供给getUserName()方法的参数id是什么,都返回一个固定的值。

我们还需要一个标准的Spring Boot主类来扫描bean并初始化应用程序:

@SpringBootApplication
public class MocksApplication {
    
    public static void main(String[] args) {
        SpringApplication.run(MocksApplication.class, args);
    }
}

3.2 测试

首先,我们必须为测试配置应用程序上下文:

@Profile("test")
@Configuration
public class NameServiceTestConfiguration {

    @Bean
    @Primary
    public NameService nameService() {
        return Mockito.mock(NameService.class);
    }
}

@Profile注解告诉Spring仅在“test” Profile处于激活状态时应用此配置。@Primary注解用于确保使用nameService()方法创建的NameService mock实例进行自动注入,而不是使用真实实例。

现在我们可以编写单元测试:

@ActiveProfiles("test")
@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = MocksApplication.class)
class UserServiceUnitTest {

    @Autowired
    private UserService userService;

    @Autowired
    private NameService nameService;

    @Test
    void whenUserIdIsProvided_thenRetrievedNameIsCorrect() {
        Mockito.when(nameService.getUserName("SomeId")).thenReturn("Mock user name");

        String testName = userService.getUserName("SomeId");

        assertEquals("Mock user name", testName);
    }
}

我们使用@ActiveProfiles注解来启用“test” Profile并激活我们之前编写的mock配置。因此,Spring会自动注入UserService类的真实实例,但是会mock NameService类。测试本身是一个相当典型的JUnit5 + Mockito测试。我们配置mock的期望行为,然后调用我们想要测试的方法,并断言它返回我们期望的值。

也可以(尽管不推荐)避免在此类测试中使用Profile。为此,我们可以删除@Profile和@ActiveProfiles注解,并将@ContextConfiguration(classes = NameServiceTestConfiguration.class)注解添加到UserServiceTest类上。

4. 总结

在这篇简短的文章中,我们介绍了如何将Mockito mock注入到Spring Bean。

与往常一样,本教程的完整源代码可在GitHub上获得。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章