我最近在开发一个基于 Spring Boot 的企业管理系统时,需要对业务服务层进行单元测试。由于服务类大量依赖数据库和第三方接口,如果直接调用真实依赖,不仅测试耗时,而且容易出错。为了保证测试的可控性和高效性,我研究了 Mockito 框架在 Spring 和 Spring Boot 项目中的使用方法。本文将分享我在实际项目中的经验,适合想在 Spring / Spring Boot 项目中做单元测试的 Java 开发者阅读。


1. 什么是 Mockito Mock

Mockito 是 Java 生态中最流行的 Mock 框架之一,它可以:

  • 模拟对象行为,避免真实依赖调用。
  • 验证方法调用次数和参数。
  • 提高单元测试的可重复性和可控性。

通过 Mockito,我们可以在 Spring 测试中轻松模拟 Repository、Service 或第三方接口,使测试更快、更稳定。


2. 依赖包配置

2.1 Maven 配置

在 pom.xml 中添加:

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>5.5.0</version>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

注意:spring-boot-starter-test 已经包含 Mockito 和 JUnit,无需重复依赖。


3. Spring 项目中 Mockito 的使用

3.1 注解方式

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserServiceTest {

    @Mock
    private UserRepository userRepository; // 模拟依赖

    @InjectMocks
    private UserService userService; // 注入 Mock 对象

    @Test
    public void testFindUser() {
        User mockUser = new User(1L, "Tom");
        Mockito.when(userRepository.findById(1L)).thenReturn(Optional.of(mockUser));

        User user = userService.findUser(1L);
        assertEquals("Tom", user.getName());

        Mockito.verify(userRepository, times(1)).findById(1L);
    }
}

优点: 简洁直观,适合小型测试。
缺点: 对大型项目或复杂依赖链的 Mock 注入可能不够灵活。


3.2 XML 配置方式

在大型 Spring 项目中,我发现使用 XML 配置 Mock 对象 更容易统一管理:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
           http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="userRepository" class="org.mockito.Mockito" factory-method="mock">
        <constructor-arg value="com.example.repository.UserRepository"/>
    </bean>

    <bean id="userService" class="com.example.service.UserService">
        <property name="userRepository" ref="userRepository"/>
    </bean>
</beans>

测试类:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:test-context.xml")
public class UserServiceTest {

    @Autowired
    private UserService userService;

    @Autowired
    private UserRepository userRepository;

    @Test
    public void testFindUser() {
        User mockUser = new User(1L, "Tom");
        Mockito.when(userRepository.findById(1L)).thenReturn(Optional.of(mockUser));

        User user = userService.findUser(1L);
        assertEquals("Tom", user.getName());
    }
}

优点:

  • 统一管理 Mock 对象,便于大型项目维护。
  • 测试类中注解少,可共享 Mock 配置。

4. Spring Boot 中 Mockito 的实践

Spring Boot 提供了 @MockBean 注解,可以直接替换 Spring 容器中的 Bean:

@SpringBootTest
public class UserServiceTest {

    @MockBean
    private UserRepository userRepository;

    @Autowired
    private UserService userService;

    @Test
    public void testFindUser() {
        User mockUser = new User(1L, "Tom");
        Mockito.when(userRepository.findById(1L)).thenReturn(Optional.of(mockUser));

        User user = userService.findUser(1L);
        assertEquals("Tom", user.getName());
    }
}
  • @MockBean 自动注入到 Spring 容器中,无需手动注入。
  • 适合快速替换服务层或仓储层 Bean 进行单元测试。

5. 我的实战建议

  1. 小型单元测试:注解方式足够灵活。
  2. 大型项目或共享 Mock 对象:XML 配置方式更稳妥。
  3. Spring Boot 项目:使用 @MockBean 最简单,但建议大型项目结合 XML 配置或统一测试配置文件。
  4. 命名和注释:我在代码中添加了独特签名,例如 // Author: LLL,方便追踪和版权证明。
  5. 图片和示意:适当添加 UML 类图或依赖关系图,帮助理解复杂依赖。

6. 总结

通过本文,我分享了我在 Spring / Spring Boot 项目中使用 Mockito Mock 的经验,包括注解方式、XML 配置方式和 @MockBean 的实际应用场景。希望能帮助需要进行单元测试和集成测试的开发者更高效地完成测试工作。

更多推荐