SpringBoot单元测试中@SpyBean使用小结
作者:zru_9602
本文主要介绍了SpringBoot单元测试中@SpyBean使用小结,@SpyBean用于部分模拟SpringBean,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
1. 什么是@SpyBean?
@SpyBean
是 Spring Boot Test 提供的一个注解,用于在单元测试中**部分模拟(Partial Mock)**一个 Spring Bean。它类似于 Mockito 的 @Spy
,但专门用于 Spring 容器中的 Bean。
- @MockBean:完全模拟一个 Bean,所有方法都需要手动定义行为。
- @SpyBean:基于真实 Bean,只重写(Mock)部分方法,其余方法仍然调用真实逻辑。
2. 何时使用@SpyBean?
✅ 适用场景:
- 你只想修改某个 Bean 的某个方法,但其他方法仍然走真实逻辑。
- 你希望测试依赖某个 Bean 的真实逻辑,但需要控制其中某个方法的返回值。
❌ 不适用场景:
- 需要完全模拟整个 Bean(用
@MockBean
)。 - Bean 的方法是
final
或static
(Mockito 无法 Spyfinal
方法)。
3. 基本用法
示例场景
假设有一个 UserService
依赖 UserRepository
,我们想测试 UserService
,但只重写 UserRepository
的 findById()
方法,其他方法(如 save()
)仍然走真实逻辑。
@Service public class UserService { @Autowired private UserRepository userRepository; public String getUserName(Long id) { User user = userRepository.findById(id).orElseThrow(); return user.getName(); } }
测试代码
@SpringBootTest public class UserServiceTest { @Autowired private UserService userService; @SpyBean // 对 UserRepository 进行 Spy,未 Mock 的方法仍然走真实逻辑 private UserRepository userRepository; @Test public void testGetUserName() { // 准备测试数据 User mockUser = new User(1L, "Alice"); userRepository.save(mockUser); // 真实调用 save() // 只 Mock findById(),让它返回自定义数据 doReturn(Optional.of(new User(1L, "Mocked Alice"))) .when(userRepository).findById(1L); // 调用测试方法 String userName = userService.getUserName(1L); // 验证 assertEquals("Mocked Alice", userName); // 其他方法仍然走真实逻辑 User savedUser = userRepository.findById(2L).orElse(null); assertNull(savedUser); // 因为没有存 ID=2 的用户 } }
4.@SpyBean的常用 Mock 方式
(1)doReturn().when(spy).method()
// 让方法返回固定值 doReturn("Mocked Result").when(mySpyBean).someMethod(); // 带参数匹配 doReturn("Hello").when(mySpyBean).greet(anyString());
(2)doAnswer()(自定义逻辑)
doAnswer(invocation -> { String arg = invocation.getArgument(0); return "Processed: " + arg; }).when(mySpyBean).process(anyString());
(3)doThrow()(模拟异常)
doThrow(new RuntimeException("DB Error")) .when(mySpyBean).save(any());
(4)doCallRealMethod()(显式调用真实方法)
// 默认会走真实方法,但也可以显式声明 doCallRealMethod().when(mySpyBean).someMethod();
5.@SpyBeanvs@MockBean
特性 | @SpyBean | @MockBean |
---|---|---|
默认行为 | 未 Mock 的方法调用真实逻辑 | 未 Mock 的方法返回默认值(null/0/false) |
适用场景 | 只修改部分方法,其他方法仍需真实逻辑 | 完全模拟 Bean,不依赖真实实现 |
性能 | 稍慢(需代理真实对象) | 更快(纯 Mock 对象) |
6. 常见问题
Q1:@SpyBean能用于final方法吗?
❌ 不能! Mockito 无法 Spy final
方法。如果遇到 final
方法,考虑:
- 改用
@MockBean
完全模拟。 - 重构代码,避免
final
方法。
Q2:@SpyBean和@Spy的区别?
@Spy
是 Mockito 提供的,用于普通对象。@SpyBean
是 Spring Boot 提供的,用于 Spring Bean。
Q3: 如何验证方法调用次数?
// 验证 someMethod 被调用 1 次 verify(mySpyBean, times(1)).someMethod();
7. 总结
@SpyBean
适合部分 Mock,只修改某些方法,其余方法仍然走真实逻辑。- 常用方式:
doReturn().when(spy).method()
:返回固定值。doAnswer()
:自定义逻辑。doThrow()
:模拟异常。
- 不要用于 final 方法。
到此这篇关于SpringBoot单元测试中@SpyBean使用小结的文章就介绍到这了,更多相关SpringBoot @SpyBean内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
您可能感兴趣的文章:
- springboot @ConditionalOnMissingBean注解的作用详解
- SpringBoot 注解事务声明式事务的方式
- springboot2中使用@JsonFormat注解不生效的解决
- SpringBoot中@Pattern注解对时间格式校验方式
- springboot FeignClient注解及参数
- SpringBoot中@ConfigurationProperties注解的使用与源码详解
- SpringBoot2.0整合SpringCloud Finchley @hystrixcommand注解找不到解决方案
- 亲测SpringBoot参数传递及@RequestBody注解---踩过的坑及解决
- 详解SpringBoot 快速整合Mybatis(去XML化+注解进阶)