使用JUnit 5和Mockito能有效隔離依賴進(jìn)行單元測(cè)試,1. 通過(guò)@Mock創(chuàng)建模擬對(duì)象,@InjectMocks注入被測(cè)實(shí)例,@ExtendWith啟用Mockito擴(kuò)展;2. 使用when().thenReturn()定義模擬行為,verify()驗(yàn)證方法調(diào)用次數(shù)與參數(shù);3. 可模擬異常場(chǎng)景并驗(yàn)證錯(cuò)誤處理;4. 推薦構(gòu)造函數(shù)注入、避免過(guò)度模擬、保持測(cè)試原子性;5. 使用assertAll()合并斷言,@Nested組織測(cè)試場(chǎng)景,從而提升測(cè)試可維護(hù)性和可靠性。
單元測(cè)試和模擬在Java中是保證代碼質(zhì)量的重要手段,而JUnit 5和Mockito是目前最流行的測(cè)試框架組合。它們配合使用,可以高效地對(duì)業(yè)務(wù)邏輯進(jìn)行隔離測(cè)試,尤其適用于依賴外部服務(wù)、數(shù)據(jù)庫(kù)或復(fù)雜對(duì)象的場(chǎng)景。

為什么使用JUnit 5 Mockito?
JUnit 5 是 Java 中主流的單元測(cè)試框架,提供了更靈活的注解模型、擴(kuò)展機(jī)制和斷言功能。Mockito 則是一個(gè)強(qiáng)大的模擬(mocking)框架,允許你創(chuàng)建和配置“假”對(duì)象來(lái)替代真實(shí)依賴,從而專注于測(cè)試目標(biāo)類(lèi)的行為。
兩者結(jié)合,能讓你:

- 隔離被測(cè)代碼與外部依賴
- 驗(yàn)證方法調(diào)用次數(shù)和參數(shù)
- 模擬異常和邊界情況
- 提高測(cè)試可維護(hù)性和執(zhí)行速度
1. 基本環(huán)境搭建
首先確保項(xiàng)目中引入了 JUnit 5 和 Mockito 的依賴。如果你使用 Maven,添加以下內(nèi)容到 pom.xml
:
<dependencies> <!-- JUnit 5 --> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <version>5.10.0</version> <scope>test</scope> </dependency> <!-- Mockito --> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>5.7.0</version> <scope>test</scope> </dependency> <!-- Mockito JUnit Jupiter 支持(可選,用于 @Mock 注解自動(dòng)初始化) --> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-junit-jupiter</artifactId> <version>5.7.0</version> <scope>test</scope> </dependency> </dependencies>
同時(shí),確保使用支持 JUnit 5 的構(gòu)建配置(如 Surefire 插件版本 >= 2.22.0)。

2. 使用 Mockito 模擬依賴對(duì)象
假設(shè)我們有一個(gè)訂單服務(wù) OrderService
,它依賴于一個(gè)支付網(wǎng)關(guān) PaymentGateway
接口:
public interface PaymentGateway { boolean charge(double amount); } public class OrderService { private final PaymentGateway paymentGateway; public OrderService(PaymentGateway paymentGateway) { this.paymentGateway = paymentGateway; } public boolean processOrder(double amount) { if (amount <= 0) return false; return paymentGateway.charge(amount); } }
我們想測(cè)試 OrderService.processOrder()
,但不想真正調(diào)用支付系統(tǒng)。這時(shí)就可以用 Mockito 創(chuàng)建一個(gè)模擬的 PaymentGateway
。
編寫(xiě)測(cè)試類(lèi)
import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; import org.mockito.Mock; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; class OrderServiceTest { @Mock private PaymentGateway paymentGateway; @InjectMocks private OrderService orderService; // 必須配合 MockitoExtension 才能自動(dòng)初始化 @Mock 和 @InjectMocks @org.junit.jupiter.api.extension.ExtendWith(MockitoExtension.class) static class Nested {} @Test void shouldReturnFalse_WhenAmountIsInvalid() { // 調(diào)用被測(cè)方法 boolean result = orderService.processOrder(-100); // 斷言結(jié)果 assertFalse(result); // 驗(yàn)證沒(méi)有調(diào)用支付網(wǎng)關(guān) verify(paymentGateway, never()).charge(anyDouble()); } @Test void shouldReturnTrue_WhenPaymentSucceeds() { // 模擬依賴行為 when(paymentGateway.charge(100.0)).thenReturn(true); // 執(zhí)行 boolean result = orderService.processOrder(100.0); // 斷言 assertTrue(result); verify(paymentGateway).charge(100.0); } @Test void shouldReturnFalse_WhenPaymentFails() { when(paymentGateway.charge(100.0)).thenReturn(false); boolean result = orderService.processOrder(100.0); assertFalse(result); verify(paymentGateway).charge(100.0); } }
關(guān)鍵點(diǎn)說(shuō)明:
@Mock
:創(chuàng)建一個(gè)模擬對(duì)象(mock)@InjectMocks
:創(chuàng)建目標(biāo)類(lèi)實(shí)例,并自動(dòng)將@Mock
標(biāo)記的字段注入進(jìn)去(通過(guò)構(gòu)造函數(shù)或字段注入)@ExtendWith(MockitoExtension.class)
:?jiǎn)⒂?Mockito 的 JUnit 擴(kuò)展,自動(dòng)初始化注解when(...).thenReturn(...)
:定義模擬方法的返回值verify(...)
:驗(yàn)證某個(gè)方法是否被調(diào)用,以及調(diào)用次數(shù)、參數(shù)等
3. 驗(yàn)證行為與交互(Behavior Verification)
除了斷言返回值,還可以驗(yàn)證方法是否被正確調(diào)用。例如:
@Test void shouldAttemptChargeExactlyOnce() { when(paymentGateway.charge(50.0)).thenReturn(true); orderService.processOrder(50.0); // 驗(yàn)證 charge 方法被調(diào)用一次,且參數(shù)為 50.0 verify(paymentGateway, times(1)).charge(eq(50.0)); }
其他常用驗(yàn)證方式:
never()
:從未被調(diào)用atLeastOnce()
:至少一次timeout(100)
:在指定時(shí)間內(nèi)被調(diào)用(用于異步)inOrder(...)
:驗(yàn)證調(diào)用順序
// 示例:驗(yàn)證調(diào)用順序 InOrder inOrder = inOrder(paymentGateway); inOrder.verify(paymentGateway).charge(30.0); inOrder.verify(paymentGateway).charge(20.0);
4. 處理異常和邊界情況
你可以讓模擬對(duì)象拋出異常,測(cè)試錯(cuò)誤處理邏輯:
@Test void shouldHandlePaymentFailureDueToException() { when(paymentGateway.charge(100.0)).thenThrow(new RuntimeException("Network error")); assertThrows(RuntimeException.class, () -> { orderService.processOrder(100.0); }); verify(paymentGateway).charge(100.0); }
也可以使用 doThrow()
配合 doReturn()
處理 void
方法或特殊場(chǎng)景。
5. 小技巧和最佳實(shí)踐
- 避免過(guò)度模擬:只模擬真正需要隔離的依賴,不要模擬整個(gè)鏈路
- 優(yōu)先使用構(gòu)造函數(shù)注入:便于測(cè)試時(shí)傳入 mock 對(duì)象
- 保持測(cè)試原子性:一個(gè)測(cè)試只驗(yàn)證一個(gè)行為
- 使用
assertAll()
批量斷言
@Test void multipleAssertions() { when(paymentGateway.charge(100.0)).thenReturn(true); boolean result = orderService.processOrder(100.0); assertAll( () -> assertTrue(result), () -> verify(paymentGateway).charge(100.0) ); }
- 使用
@Nested
測(cè)試類(lèi)組織不同場(chǎng)景:
@Nested class WhenAmountIsPositive { @Test void shouldChargePaymentGateway() { ... } }
基本上就這些。JUnit 5 Mockito 的組合讓 Java 單元測(cè)試變得直觀又強(qiáng)大。關(guān)鍵是理解“測(cè)試行為”而非“測(cè)試實(shí)現(xiàn)”,并通過(guò) mock 控制依賴,確保測(cè)試快速、穩(wěn)定、可重復(fù)。
以上是使用Junit 5和Mockito在Java進(jìn)行單位測(cè)試和嘲笑的詳細(xì)內(nèi)容。更多信息請(qǐng)關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

熱AI工具

Undress AI Tool
免費(fèi)脫衣服圖片

Undresser.AI Undress
人工智能驅(qū)動(dòng)的應(yīng)用程序,用于創(chuàng)建逼真的裸體照片

AI Clothes Remover
用于從照片中去除衣服的在線人工智能工具。

Clothoff.io
AI脫衣機(jī)

Video Face Swap
使用我們完全免費(fèi)的人工智能換臉工具輕松在任何視頻中換臉!

熱門(mén)文章

熱工具

記事本++7.3.1
好用且免費(fèi)的代碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
功能強(qiáng)大的PHP集成開(kāi)發(fā)環(huán)境

Dreamweaver CS6
視覺(jué)化網(wǎng)頁(yè)開(kāi)發(fā)工具

SublimeText3 Mac版
神級(jí)代碼編輯軟件(SublimeText3)

懶加載在訪問(wèn)關(guān)聯(lián)時(shí)才查詢,易導(dǎo)致N 1問(wèn)題,適合不確定是否需要關(guān)聯(lián)數(shù)據(jù)的場(chǎng)景;2.急加載使用with()提前加載關(guān)聯(lián)數(shù)據(jù),避免N 1查詢,適合批量處理場(chǎng)景;3.應(yīng)優(yōu)先使用急加載優(yōu)化性能,可通過(guò)LaravelDebugbar等工具檢測(cè)N 1問(wèn)題,并謹(jǐn)慎使用模型的$with屬性以避免不必要的性能開(kāi)銷(xiāo)。

usearestapitobridgephpandmlmodelsbyrunningthemodelinpythonviaflaskorfastapiandcallingitfromphpusingcurlorguzzle.2.runpythonscriptsdirectsdirectlyectlyectlyfromphpsingexec()orshell_exec()orshell_exec()orshell_exec()

Laravel支持使用原生SQL查詢,但應(yīng)優(yōu)先使用參數(shù)綁定以確保安全;1.使用DB::select()執(zhí)行帶參數(shù)綁定的SELECT查詢,防止SQL注入;2.使用DB::update()執(zhí)行UPDATE操作并返回影響行數(shù);3.使用DB::insert()插入數(shù)據(jù);4.使用DB::delete()刪除數(shù)據(jù);5.使用DB::statement()執(zhí)行如CREATE、ALTER等無(wú)結(jié)果集的SQL語(yǔ)句;6.推薦在QueryBuilder中使用whereRaw、selectRaw等方法結(jié)合原生表達(dá)式以提升安

響應(yīng)式編程在Java中通過(guò)ProjectReactor和SpringWebFlux實(shí)現(xiàn)高并發(fā)、低延遲的非阻塞服務(wù)。1.ProjectReactor提供Mono和Flux兩個(gè)核心類(lèi)型,支持聲明式處理異步數(shù)據(jù)流,并通過(guò)操作符鏈進(jìn)行轉(zhuǎn)換、過(guò)濾等操作;2.SpringWebFlux基于Reactor構(gòu)建,支持注解式和函數(shù)式兩種編程模型,運(yùn)行在Netty等非阻塞服務(wù)器上,可高效處理大量并發(fā)連接;3.使用WebFlux Reactor能提升I/O密集型場(chǎng)景下的并發(fā)能力與資源利用率,天然支持SSE、WebSo

JWT是一種用于安全傳輸信息的開(kāi)放標(biāo)準(zhǔn),在Java中可通過(guò)JJWT庫(kù)實(shí)現(xiàn)認(rèn)證與授權(quán),1.添加JJWT的API、Impl和Jackson依賴;2.創(chuàng)建JwtUtil工具類(lèi)生成、解析和驗(yàn)證Token;3.編寫(xiě)JwtFilter攔截請(qǐng)求并校驗(yàn)Authorization頭中的BearerToken;4.在SpringBoot中注冊(cè)Filter保護(hù)指定路徑;5.提供登錄接口在驗(yàn)證用戶后返回JWT;6.受保護(hù)接口通過(guò)解析Token獲取用戶身份和角色進(jìn)行訪問(wèn)控制,最終實(shí)現(xiàn)無(wú)狀態(tài)、可擴(kuò)展的安全機(jī)制,適合分布式系

Go泛型從1.18開(kāi)始支持,用于編寫(xiě)類(lèi)型安全的通用代碼。1.泛型函數(shù)PrintSlice[Tany](s[]T)可打印任意類(lèi)型切片,如[]int或[]string。2.通過(guò)類(lèi)型約束Number限制T為int、float等數(shù)字類(lèi)型,實(shí)現(xiàn)Sum[TNumber](slice[]T)T安全求和。3.泛型結(jié)構(gòu)體typeBox[Tany]struct{ValueT}可封裝任意類(lèi)型值,配合NewBox[Tany](vT)*Box[T]構(gòu)造函數(shù)使用。4.為Box[T]添加Set(vT)和Get()T方法,無(wú)需

table-layout:fixed會(huì)強(qiáng)制表格列寬由第一行單元格寬度決定,避免內(nèi)容影響布局。1.設(shè)置table-layout:fixed并指定表格寬度;2.為第一行th/td設(shè)置具體列寬比例;3.配合white-space:nowrap、overflow:hidden和text-overflow:ellipsis控制文本溢出;4.適用于后臺(tái)管理、數(shù)據(jù)報(bào)表等需穩(wěn)定布局和高性能渲染的場(chǎng)景,能有效防止布局抖動(dòng)并提升渲染效率。

使用JUnit5和Mockito能有效隔離依賴進(jìn)行單元測(cè)試,1.通過(guò)@Mock創(chuàng)建模擬對(duì)象,@InjectMocks注入被測(cè)實(shí)例,@ExtendWith啟用Mockito擴(kuò)展;2.使用when().thenReturn()定義模擬行為,verify()驗(yàn)證方法調(diào)用次數(shù)與參數(shù);3.可模擬異常場(chǎng)景并驗(yàn)證錯(cuò)誤處理;4.推薦構(gòu)造函數(shù)注入、避免過(guò)度模擬、保持測(cè)試原子性;5.使用assertAll()合并斷言,@Nested組織測(cè)試場(chǎng)景,從而提升測(cè)試可維護(hù)性和可靠性。
