Java Service层单元测试需禁用Spring容器与真实依赖,仅用Mockito隔离外部组件;依赖仅引入spring-boot-starter-test,使用@ExtendWith(MockitoExtension.class)、@Mock和@InjectMocks,遵循“输入→行为→输出”验证逻辑。

Java 中对 Service 层做 Mock 单元测试,核心是不启动 Spring 容器、不连数据库、不调真实依赖,只验证自己写的业务逻辑是否正确。关键靠 Mockito 隔离外部组件,比如 Repository、其他 Service 或工具类。
依赖配置要精简到位
确保 pom.xml 里只加这一个测试依赖:
-
spring-boot-starter-test(已内置 JUnit 5、Mockito、AssertJ 等) - 不用单独引
mockito-core或junit:junit(除非项目强制用 JUnit 4) - 删掉
@SpringBootTest和@RunWith相关注解——它们会拉起完整上下文,属于集成测试范畴
测试类结构要干净清晰
用标准 JUnit 5 + Mockito 写法:
- 加
@ExtendWith(MockitoExtension.class)启用 Mockito 支持 - 用
@Mock声明要模拟的依赖(如UserRepository) - 用
@InjectMocks声明被测 Service(如UserServiceImpl),框架自动注入所有@Mock对象 - 不手写
new UserServiceImpl(),也不用@Autowired
测试过程聚焦“输入→行为→输出”
每个测试方法围绕一个明确场景展开:
立即学习“Java免费学习笔记(深入)”;
-
准备输入:构造参数 + 设置 mock 返回值,例如:
when(userRepo.findById(1L)).thenReturn(Optional.of(user)); -
执行动作:调用被测方法,例如:
User result = userService.getUserById(1L); -
验证结果:检查三类东西
✓ 返回值是否符合预期(assertEquals("Alice", result.getName()))
✓ 是否按预期调用了依赖(verify(userRepo, times(1)).findById(1L))
✓ 是否抛出指定异常(assertThrows<usernotfoundexception>(() -> userService.getUserById(999L))</usernotfoundexception>)
避开几个典型坑
这些做法会让测试变慢、不稳定或失去意义:
- 在 Service 单元测试里读
application.yml或用@Value注入配置——应把配置项抽成方法参数或常量,方便控制 - 测试纯委托方法(如
return userRepo.save(u))——没分支、没判断、没转换,无需覆盖 - 过度 mock 静态方法或私有方法——优先考虑重构为可注入 Bean;真需 mock 私有方法时,才引入 PowerMock,但应视为临时方案


















