1. 概述

在本篇文章中,我们将探讨如何通过依赖注入的方式,将 Mockito 的 Mock 对象注入到 Spring Bean 中,用于单元测试。

在真实项目中,组件往往依赖外部系统(如数据库、远程服务等),为了保证测试的独立性,我们通常需要对这些依赖进行 Mock,从而专注于被测单元本身的逻辑。使用 Mock 是一种非常干净且有效的隔离手段。

2. Maven 依赖

我们需要以下 Maven 依赖来支持单元测试和 Mock 对象的创建:

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

本例使用 Spring Boot 进行演示,当然传统 Spring 项目也完全适用。

3. 编写测试

3.1. 业务逻辑

首先,我们创建一个简单的 Service 类,作为被依赖的服务:

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

然后在另一个 Service 中注入它:

@Service
public class UserService {

    private NameService nameService;

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

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

为避免逻辑干扰,这里无论传入什么 ID 都返回固定值。

我们还需要一个标准的 Spring Boot 启动类用于扫描和初始化 Bean:

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

3.2. 测试逻辑

首先配置测试专用的 Spring 配置类:

@Profile("test")
@Configuration
public class NameServiceTestConfiguration {
    @Bean
    @Primary
    public NameService nameService() {
        return Mockito.mock(NameService.class);
    }
}
  • @Profile("test"):仅在 test 环境激活时加载该配置。
  • @Primary:确保 Spring 优先使用这个 Mock 实例,而不是真实的 Bean。
  • Mockito.mock(NameService.class):创建一个 NameService 的 Mock 对象。

接着编写单元测试类:

@ActiveProfiles("test")
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = MocksApplication.class)
public class UserServiceUnitTest {

    @Autowired
    private UserService userService;

    @Autowired
    private NameService nameService;

    @Test
    public void whenUserIdIsProvided_thenRetrievedNameIsCorrect() {
        Mockito.when(nameService.getUserName("SomeId")).thenReturn("Mock user name");
        String testName = userService.getUserName("SomeId");
        Assert.assertEquals("Mock user name", testName);
    }
}

✅ 关键点如下:

  • @ActiveProfiles("test"):启用 test profile,激活 Mock 配置。
  • @Autowired 注入真实的 UserService 和 Mock 的 NameService
  • 使用 Mockito.when(...).thenReturn(...) 设置 Mock 行为。
  • 最后验证调用结果是否符合预期。

⚠️ 也可以不使用 Profile 来实现 Mock 注入,但不推荐

  • 移除 @Profile@ActiveProfiles
  • 添加 @ContextConfiguration(classes = NameServiceTestConfiguration.class) 到测试类上。

但这样容易污染全局配置,踩坑风险较高。

4. 总结

本文展示了如何简单粗暴地将 Mockito Mock 对象注入到 Spring Bean 中,实现干净的单元测试隔离。

所有示例代码均可在 GitHub 获取。


原始标题:Injecting Mockito Mocks in to Spring Beans | Baeldung