亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

目錄
問題剖析:Mockito Spy的常見誤區(qū)
解決方案:擁抱依賴注入
1. 構造函數注入
2. 方法注入
依賴注入的優(yōu)勢
總結與最佳實踐
首頁 Java java教程 解決Mockito Spy方法未被調用:深度解析與依賴注入實踐

解決Mockito Spy方法未被調用:深度解析與依賴注入實踐

Aug 04, 2025 pm 07:06 PM

解決Mockito Spy方法未被調用:深度解析與依賴注入實踐

本文旨在解決使用Mockito spy時,被樁(stub)方法未按預期執(zhí)行的問題。核心原因在於生產代碼直接實例化依賴對象,而非使用測試中創(chuàng)建的間諜對象。文章將詳細闡述這一常見誤區(qū),並提供通過依賴注入(Dependency Injection)進行解耦的解決方案,從而有效提升代碼的可測試性與模塊化程度。

問題剖析:Mockito Spy的常見誤區(qū)

在單元測試中,Mockito 的spy 功能允許我們對一個真實對象進行部分模擬,即可以調用真實對象的方法,也可以對特定方法進行樁(stub)或驗證(verify)。然而,一個常見的誤解是,當生產代碼(即被測試的代碼)內部直接創(chuàng)建了它所依賴的對象實例時,測試中創(chuàng)建的spy 對象將無法生效。

考慮以下生產代碼片段,其中MyService 類直接創(chuàng)建了GetOptionBidPrice 的實例:

 // 生產代碼public class MyService {
    public double calculateBidPrice() {
        // 問題所在:MyService 內部直接實例化GetOptionBidPrice
        GetOptionBidPrice getOptionBidPrice = new GetOptionBidPrice(/* 構造參數*/);
        double bidPrice = getOptionBidPrice.getBidPrice();
        return bidPrice;
    }
}

// 被依賴的類public class GetOptionBidPrice {
    // 假設有構造函數和getBidPrice方法public GetOptionBidPrice(/* 構造參數*/) {
        // ... 初始化...
    }

    public double getBidPrice() {
        // 真實業(yè)務邏輯,可能返回0.0或其他默認值return 0.0;
    }
}

在嘗試測試MyService 時,我們可能會這樣編寫測試代碼,試圖樁化getBidPrice 方法:

 // 測試代碼(錯誤示範)
import org.junit.jupiter.api.Test;
import static org.mockito.Mockito.*;

public class MyServiceTest {

    @Test
    void testCalculateBidPriceWithSpy() {
        // 1. 創(chuàng)建MyService 實例MyService myService = new MyService();

        // 2. 創(chuàng)建GetOptionBidPrice 的間諜對象並樁化其方法// 注意:這裡創(chuàng)建的spyGetOptionBidPrice 是一個獨立的實例GetOptionBidPrice spyGetOptionBidPrice = spy(new GetOptionBidPrice(/* 構造參數*/));
        doReturn(100.0).when(spyGetOptionBidPrice).getBidPrice();

        // 3. 調用MyService 的方法double result = myService.calculateBidPrice();

        // 預期結果是100.0,但實際結果會是0.0
        // 因為myService 內部創(chuàng)建了一個全新的GetOptionBidPrice 實例,而不是我們樁化的spyGetOptionBidPrice
        System.out.println("實際結果: " result); // 輸出0.0
        // assertEquals(100.0, result); // 斷言失敗}
}

問題根源:上述測試代碼的問題在於,MyService 內部的calculateBidPrice 方法在執(zhí)行時,會通過new GetOptionBidPrice() 語句重新創(chuàng)建一個全新的GetOptionBidPrice 實例。這個新實例與我們在測試中創(chuàng)建並樁化的spyGetOptionBidPrice 實例是完全不同的兩個對象。因此,MyService 內部調用的getBidPrice() 方法是新實例的真實方法,而不是間諜對像上被樁化的方法,導致樁化操作未能生效。

解決方案:擁抱依賴注入

解決這一問題的核心思想是:將依賴對象的創(chuàng)建和管理從被依賴類中分離出來,讓被依賴類不再直接負責創(chuàng)建其依賴。這種設計模式被稱為依賴注入(Dependency Injection, DI) 。通過依賴注入,我們可以在測試時注入一個spy 或mock 對象,而在生產環(huán)境中註入真實對象。

依賴注入有多種實現方式,最常見的是構造函數注入方法注入。

1. 構造函數注入

這是最推薦的方式,尤其適用於強制性依賴。被依賴對像在構造時就接收其所有依賴。

改造後的生產代碼:

 // 生產代碼(使用構造函數注入)
public class MyService {
    private final GetOptionBidPrice getOptionBidPrice;

    // 依賴通過構造函數注入public MyService(GetOptionBidPrice getOptionBidPrice) {
        this.getOptionBidPrice = getOptionBidPrice;
    }

    public double calculateBidPrice() {
        // 現在MyService 使用的是注入進來的GetOptionBidPrice 實例return getOptionBidPrice.getBidPrice();
    }
}

改造後的測試代碼:

 // 測試代碼(使用構造函數注入)
import org.junit.jupiter.api.Test;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class MyServiceTest {

    @Test
    void testCalculateBidPriceWithInjectedSpy() {
        // 1. 創(chuàng)建GetOptionBidPrice 的間諜對象並樁化其方法GetOptionBidPrice spyGetOptionBidPrice = spy(new GetOptionBidPrice(/* 構造參數*/));
        doReturn(100.0).when(spyGetOptionBidPrice).getBidPrice();

        // 2. 將間諜對象注入到MyService 實例中MyService myService = new MyService(spyGetOptionBidPrice);

        // 3. 調用MyService 的方法double result = myService.calculateBidPrice();

        // 現在,MyService 內部調用的是我們注入的間諜對象的getBidPrice() 方法assertEquals(100.0, result);
        verify(spyGetOptionBidPrice).getBidPrice(); // 驗證方法是否被調用}
}

2. 方法注入

如果依賴不是每次操作都必須的,或者需要在特定方法執(zhí)行時才提供,可以使用方法注入。

改造後的生產代碼:

 // 生產代碼(使用方法注入)
public class MyService {
    public double calculateBidPrice(GetOptionBidPrice getOptionBidPrice) {
        // 依賴通過方法參數注入return getOptionBidPrice.getBidPrice();
    }
}

改造後的測試代碼:

 // 測試代碼(使用方法注入)
import org.junit.jupiter.api.Test;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class MyServiceTest {

    @Test
    void testCalculateBidPriceWithMethodInjectedSpy() {
        // 1. 創(chuàng)建GetOptionBidPrice 的間諜對象並樁化其方法GetOptionBidPrice spyGetOptionBidPrice = spy(new GetOptionBidPrice(/* 構造參數*/));
        doReturn(100.0).when(spyGetOptionBidPrice).getBidPrice();

        // 2. 創(chuàng)建MyService 實例MyService myService = new MyService();

        // 3. 調用MyService 的方法時,將間諜對像作為參數傳入double result = myService.calculateBidPrice(spyGetOptionBidPrice);

        assertEquals(100.0, result);
        verify(spyGetOptionBidPrice).getBidPrice();
    }
}

依賴注入的優(yōu)勢

除了解決spy 不生效的問題,依賴注入還帶來了多方面的好處:

  • 提高可測試性:模塊之間的依賴關係清晰,方便在測試中替換為mock 或spy 對象,從而隔離測試範圍,實現真正的單元測試。
  • 降低耦合度:對像不再直接負責創(chuàng)建和管理其依賴,而是由外部(如IoC 容器或測試代碼)提供,使得模塊之間的耦合度降低,更易於維護和修改。
  • 提升代碼可維護性和擴展性:當依賴發(fā)生變化時,只需修改注入點,而無需修改依賴類內部的創(chuàng)建邏輯。這使得系統(tǒng)更容易適應需求變化。
  • 更好的代碼結構:強制開發(fā)者思考模塊間的依賴關係,有助於設計出更清晰、更符合單一職責原則的類。

總結與最佳實踐

當您在使用Mockito 的spy 或mock 功能時發(fā)現樁化或模擬的行為未能按預期執(zhí)行,一個首要的排查方向就是檢查您的生產代碼是否直接實例化了其依賴。如果是,那麼依賴注入就是解決這個問題的關鍵。

關鍵點:

  • 避免在被測試類內部直接new 依賴對象。
  • 優(yōu)先使用構造函數注入來處理強制性依賴。
  • 考慮使用方法注入處理可選或上下文相關的依賴。
  • 利用Mockito 的@InjectMocks 和@Mock/@Spy 註解可以簡化測試代碼,Mockito 會嘗試自動注入依賴。

通過採納依賴注入模式,不僅能有效解決Mockito spy 的使用問題,更能從根本上提升代碼的質量、可測試性和可維護性,是現代軟件開發(fā)中不可或缺的設計實踐。

以上是解決Mockito Spy方法未被調用:深度解析與依賴注入實踐的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發(fā)現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創(chuàng)建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Laravel 教程
1597
29
PHP教程
1488
72
Java中可呼叫和可運行的差異 Java中可呼叫和可運行的差異 Jul 04, 2025 am 02:50 AM

Callable和Runnable在Java中主要有三點區(qū)別。第一,Callable的call()方法可以返回結果,適合需要返回值的任務,如Callable;而Runnable的run()方法無返回值,適用於無需返回的任務,如日誌記錄。第二,Callable允許拋出checked異常,便於錯誤傳遞;而Runnable必須在內部處理異常。第三,Runnable可直接傳給Thread或ExecutorService,而Callable只能提交給ExecutorService,並返回Future對像以

現代爪哇的異步編程技術 現代爪哇的異步編程技術 Jul 07, 2025 am 02:24 AM

Java支持異步編程的方式包括使用CompletableFuture、響應式流(如ProjectReactor)以及Java19 中的虛擬線程。 1.CompletableFuture通過鍊式調用提升代碼可讀性和維護性,支持任務編排和異常處理;2.ProjectReactor提供Mono和Flux類型實現響應式編程,具備背壓機制和豐富的操作符;3.虛擬線程減少並發(fā)成本,適用於I/O密集型任務,與傳統(tǒng)平臺線程相比更輕量且易於擴展。每種方式均有適用場景,應根據需求選擇合適工具並避免混合模型以保持簡潔性

在Java中使用枚舉的最佳實踐 在Java中使用枚舉的最佳實踐 Jul 07, 2025 am 02:35 AM

在Java中,枚舉(enum)適合表示固定常量集合,最佳實踐包括:1.用enum表示固定狀態(tài)或選項,提升類型安全和可讀性;2.為枚舉添加屬性和方法以增強靈活性,如定義字段、構造函數、輔助方法等;3.使用EnumMap和EnumSet提高性能和類型安全性,因其基於數組實現更高效;4.避免濫用enum,如動態(tài)值、頻繁變更或複雜邏輯場景應使用其他方式替代。正確使用enum能提升代碼質量並減少錯誤,但需注意其適用邊界。

了解Java Nio及其優(yōu)勢 了解Java Nio及其優(yōu)勢 Jul 08, 2025 am 02:55 AM

JavaNIO是Java1.4引入的新型IOAPI,1)面向緩衝區(qū)和通道,2)包含Buffer、Channel和Selector核心組件,3)支持非阻塞模式,4)相比傳統(tǒng)IO更高效處理並發(fā)連接。其優(yōu)勢體現在:1)非阻塞IO減少線程開銷,2)Buffer提升數據傳輸效率,3)Selector實現多路復用,4)內存映射加快文件讀寫。使用時需注意:1)Buffer的flip/clear操作易混淆,2)非阻塞下需手動處理不完整數據,3)Selector註冊需及時取消,4)NIO並非適用於所有場景。

Java Classloader在內部如何工作 Java Classloader在內部如何工作 Jul 06, 2025 am 02:53 AM

Java的類加載機制通過ClassLoader實現,其核心工作流程分為加載、鏈接和初始化三個階段。加載階段由ClassLoader動態(tài)讀取類的字節(jié)碼並創(chuàng)建Class對象;鏈接包括驗證類的正確性、為靜態(tài)變量分配內存及解析符號引用;初始化則執(zhí)行靜態(tài)代碼塊和靜態(tài)變量賦值。類加載採用雙親委派模型,優(yōu)先委託父類加載器查找類,依次嘗試Bootstrap、Extension和ApplicationClassLoader,確保核心類庫安全且避免重複加載。開發(fā)者可自定義ClassLoader,如URLClassL

探索Java中不同的同步機制 探索Java中不同的同步機制 Jul 04, 2025 am 02:53 AM

Javaprovidesmultiplesynchronizationtoolsforthreadsafety.1.synchronizedblocksensuremutualexclusionbylockingmethodsorspecificcodesections.2.ReentrantLockoffersadvancedcontrol,includingtryLockandfairnesspolicies.3.Conditionvariablesallowthreadstowaitfor

有效處理常見的Java例外 有效處理常見的Java例外 Jul 05, 2025 am 02:35 AM

Java異常處理的關鍵在於區(qū)分checked和unchecked異常並合理使用try-catch、finally及日誌記錄。 1.checked異常如IOException需強制處理,適用於可預期的外部問題;2.unchecked異常如NullPointerException通常由程序邏輯錯誤引起,屬於運行時錯誤;3.捕獲異常時應具體明確,避免籠統(tǒng)捕獲Exception;4.推薦使用try-with-resources自動關閉資源,減少手動清理代碼;5.異常處理中應結合日誌框架記錄詳細信息,便於後

Hashmap在Java內部如何工作? Hashmap在Java內部如何工作? Jul 15, 2025 am 03:10 AM

HashMap在Java中通過哈希表實現鍵值對存儲,其核心在於快速定位數據位置。 1.首先使用鍵的hashCode()方法生成哈希值,並通過位運算轉換為數組索引;2.不同對象可能產生相同哈希值,導致衝突,此時以鍊錶形式掛載節(jié)點,JDK8後鍊錶過長(默認長度8)則轉為紅黑樹提升效率;3.使用自定義類作鍵時必須重寫equals()和hashCode()方法;4.HashMap動態(tài)擴容,當元素數超過容量乘以負載因子(默認0.75)時,擴容並重新哈希;5.HashMap非線程安全,多線程下應使用Concu

See all articles