SpringBoot單元測試中@SpyBean使用小結(jié)
1. 什么是@SpyBean?
@SpyBean
是 Spring Boot Test 提供的一個注解,用于在單元測試中**部分模擬(Partial Mock)**一個 Spring Bean。它類似于 Mockito 的 @Spy
,但專門用于 Spring 容器中的 Bean。
- @MockBean:完全模擬一個 Bean,所有方法都需要手動定義行為。
- @SpyBean:基于真實(shí) Bean,只重寫(Mock)部分方法,其余方法仍然調(diào)用真實(shí)邏輯。
2. 何時使用@SpyBean?
? 適用場景:
- 你只想修改某個 Bean 的某個方法,但其他方法仍然走真實(shí)邏輯。
- 你希望測試依賴某個 Bean 的真實(shí)邏輯,但需要控制其中某個方法的返回值。
? 不適用場景:
- 需要完全模擬整個 Bean(用
@MockBean
)。 - Bean 的方法是
final
或static
(Mockito 無法 Spyfinal
方法)。
3. 基本用法
示例場景
假設(shè)有一個 UserService
依賴 UserRepository
,我們想測試 UserService
,但只重寫 UserRepository
的 findById()
方法,其他方法(如 save()
)仍然走真實(shí)邏輯。
@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 進(jìn)行 Spy,未 Mock 的方法仍然走真實(shí)邏輯 private UserRepository userRepository; @Test public void testGetUserName() { // 準(zhǔn)備測試數(shù)據(jù) User mockUser = new User(1L, "Alice"); userRepository.save(mockUser); // 真實(shí)調(diào)用 save() // 只 Mock findById(),讓它返回自定義數(shù)據(jù) doReturn(Optional.of(new User(1L, "Mocked Alice"))) .when(userRepository).findById(1L); // 調(diào)用測試方法 String userName = userService.getUserName(1L); // 驗(yàn)證 assertEquals("Mocked Alice", userName); // 其他方法仍然走真實(shí)邏輯 User savedUser = userRepository.findById(2L).orElse(null); assertNull(savedUser); // 因?yàn)闆]有存 ID=2 的用戶 } }
4.@SpyBean的常用 Mock 方式
(1)doReturn().when(spy).method()
// 讓方法返回固定值 doReturn("Mocked Result").when(mySpyBean).someMethod(); // 帶參數(shù)匹配 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()(顯式調(diào)用真實(shí)方法)
// 默認(rèn)會走真實(shí)方法,但也可以顯式聲明 doCallRealMethod().when(mySpyBean).someMethod();
5.@SpyBeanvs@MockBean
特性 | @SpyBean | @MockBean |
---|---|---|
默認(rèn)行為 | 未 Mock 的方法調(diào)用真實(shí)邏輯 | 未 Mock 的方法返回默認(rèn)值(null/0/false) |
適用場景 | 只修改部分方法,其他方法仍需真實(shí)邏輯 | 完全模擬 Bean,不依賴真實(shí)實(shí)現(xiàn) |
性能 | 稍慢(需代理真實(shí)對象) | 更快(純 Mock 對象) |
6. 常見問題
Q1:@SpyBean能用于final方法嗎?
? 不能! Mockito 無法 Spy final
方法。如果遇到 final
方法,考慮:
- 改用
@MockBean
完全模擬。 - 重構(gòu)代碼,避免
final
方法。
Q2:@SpyBean和@Spy的區(qū)別?
@Spy
是 Mockito 提供的,用于普通對象。@SpyBean
是 Spring Boot 提供的,用于 Spring Bean。
Q3: 如何驗(yàn)證方法調(diào)用次數(shù)?
// 驗(yàn)證 someMethod 被調(diào)用 1 次 verify(mySpyBean, times(1)).someMethod();
7. 總結(jié)
@SpyBean
適合部分 Mock,只修改某些方法,其余方法仍然走真實(shí)邏輯。- 常用方式:
doReturn().when(spy).method()
:返回固定值。doAnswer()
:自定義邏輯。doThrow()
:模擬異常。
- 不要用于 final 方法。
到此這篇關(guān)于SpringBoot單元測試中@SpyBean使用小結(jié)的文章就介紹到這了,更多相關(guān)SpringBoot @SpyBean內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- springboot @ConditionalOnMissingBean注解的作用詳解
- SpringBoot 注解事務(wù)聲明式事務(wù)的方式
- springboot2中使用@JsonFormat注解不生效的解決
- SpringBoot中@Pattern注解對時間格式校驗(yàn)方式
- springboot FeignClient注解及參數(shù)
- SpringBoot中@ConfigurationProperties注解的使用與源碼詳解
- SpringBoot2.0整合SpringCloud Finchley @hystrixcommand注解找不到解決方案
- 親測SpringBoot參數(shù)傳遞及@RequestBody注解---踩過的坑及解決
- 詳解SpringBoot 快速整合Mybatis(去XML化+注解進(jìn)階)
相關(guān)文章
java 調(diào)用wsdl協(xié)議接口簡單實(shí)用方法最新推薦
文章介紹了如何使用POM導(dǎo)入依賴,并編寫一個測試類來調(diào)用不同的Web服務(wù)接口,通過訪問接口地址,我們可以獲取請求和返回的body,并進(jìn)一步解析返回的JSON結(jié)果,感興趣的朋友一起看看吧2025-03-03使用Java解析JSON數(shù)據(jù)并提取特定字段的實(shí)現(xiàn)步驟(以提取mailNo為例)
在現(xiàn)代軟件開發(fā)中,處理JSON數(shù)據(jù)是一項(xiàng)非常常見的任務(wù),無論是從API接口獲取數(shù)據(jù),還是將數(shù)據(jù)存儲為JSON格式,解析和提取JSON中的特定字段都是開發(fā)人員需要掌握的基本技能,本文將以一個實(shí)際案例為例,詳細(xì)介紹如何使用Java解析JSON數(shù)據(jù)并提取其中的mailNo字段2025-01-01java實(shí)現(xiàn)excel導(dǎo)出合并單元格的步驟詳解
這篇文章主要介紹了java實(shí)現(xiàn)excel導(dǎo)出合并單元格,通過使用Apache POI庫,我們可以方便地創(chuàng)建Excel文件、填充數(shù)據(jù)、合并單元格和導(dǎo)出Excel文件,需要的朋友可以參考下2023-04-04java學(xué)習(xí)筆記之eclipse+tomcat 配置
俗話說:工欲善其事必先利其器,既然要學(xué)習(xí)java,首先把java的開發(fā)環(huán)境搗鼓一下吧,這里我們來談?wù)別clipse+tomcat的配置方法。2014-11-11基于params、@PathVariabl和@RequestParam的用法與區(qū)別說明
這篇文章主要介紹了方法參數(shù)相關(guān)屬性params、@PathVariabl和@RequestParam用法與區(qū)別,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08Java實(shí)現(xiàn)將二叉樹展開為鏈表的兩種方法
文章介紹了兩種方法將二叉樹按前序遍歷順序展開為單鏈表,方法一為迭代法,方法二為前序遍歷+列表重建,兩者各有優(yōu)缺點(diǎn),選擇時需根據(jù)實(shí)際需求和場景考慮,下面小編給大家詳細(xì)說說2025-05-05分析Java非阻塞算法Lock-Free的實(shí)現(xiàn)
非阻塞算法一般會使用CAS來協(xié)調(diào)線程的操作。雖然非阻塞算法有諸多優(yōu)點(diǎn),但是在實(shí)現(xiàn)上要比基于鎖的算法更加繁瑣和負(fù)責(zé)。本文將會介紹兩個是用非阻塞算法實(shí)現(xiàn)的數(shù)據(jù)結(jié)構(gòu)。2021-06-06