2011-11-08 67 views
7

我讀過最讓相關的問題(hereherethere)。 最後一個問題提出了四種替代方法來製作調用靜態方法單元測試的代碼。 我想問一下我的具體情況:我們有一個包含45個靜態類(無狀態,只是靜態方法)的「業務邏輯層」或「規則」項目。而且,它們本身不容易測試:它們大多數都訪問數據庫和文件系統。無論如何,它並沒有那麼糟糕:爲了訪問數據庫,他們使用了一些Mapper類的獨特實例(所有映射器都是單例)。每當我嘗試單元測試的東西,我碰到這堵牆。最大的問題是這是非常非常重要的代碼,並且應該非常小心地對其進行更改。 我的問題:我應該如何去做更多的單元測試?我應該寫45個接口並使用依賴注入嗎?即便如此,我如何存根/模擬Mappers?單元測試代碼調用靜態方法

PS:我一直在閱讀邁克爾羽毛‘與遺留代碼一起工作’,所以直接引用歡迎(其他書籍太:)

編輯:因爲有些人說的解決方案可能是依賴於平臺的,我正在.NET(C#和VB.NET一些)

回答

10

目前的情況可能是,沒有人敢改變代碼中的任何東西,因爲它可能以意想不到的方式破壞。確保每個人都明白,你正在改善的情況:您的更改可能破解的代碼,但不像之前,這些破損將發現一旦他們已經發現,他們將被固定永遠

也就是說,下一步取決於你的經驗和你對團隊的信任。如果你要玩的安全,這樣使用(Java語法)代碼:

Mapper { 
    public static Mapper INSTANCE = new Mapper(); // NEW code 

    protected void doImpl() { // NEW CODE 
     ... code copied from impl()... // OLD code, NEW PLACE 
    } 

    public static void impl() { // OLD code 
     INSTANCE.doImpl(); // NEW code 
    } 

    // OLD code ... 
} 

這是一個非常簡單的變化,它允許您覆蓋從你的測試INSTANCE。對於產品代碼,您不會執行任何操作,並且默認設置會使代碼的行爲與以前完全相同。

這樣,您可以一次替換一個方法。您可以隨時停止遵循此路徑 - 每次更改只需幾分鐘,這是一次重構:代碼完全按照之前的操作進行。由於每次更改都很小,不能破壞任何內容,因此您可以更換一種方法,寫出之前無法寫入的所有單元測試,沖洗並重復。最後,如果你不想/不需要重做所有的靜態方法,這種方法給你所有的可以請求的餘地。

第二步,您可以引入DI或任何其他技術,這些技術會讓您開心。這種方法的優點是:當你遇到複雜的變化時,你已經有了可以保護你的單元測試。

如果你是從DI開始的,你將不得不在各種地方改變很多代碼 - 沒有適當的單元測試可以保護你。

2

你的問題實在是平臺相關的,在微軟的世界,你可以使用Microsoft痣測試靜態方法。並模擬靜態方法。

在Java世界中可能有其他工具或應該避免使用靜電。

在其他平臺上也有其他的工具等

一般來說,任何靜態方法會讓你的代碼少測試。在我的選擇中,不惜任何代價避免靜態和單身(全局狀態)。如果您稍後要更改什麼,可測試代碼是代碼中最重要的部分。可測試代碼通常也更具可讀性。

Moles and Pex

3

使映射器類的接口,並用新的MOC實現來替代映射器功能。我認爲你需要實現抽象工廠來生成Mappers的實例。因此,創建一個IMapperFactory,並且此DBMapperFactory和MocMapperFactory的兩個實現將此對象的實例傳遞給您訪問Mappers並使用此實例生成這些對象的代碼。

GI。

+1

聽起來沒問題。這會使靜態方法成爲可測試的,但是如何調用它們的代碼呢?另一個說明,只是好奇......是「GI」某種簽名,還是它的縮寫? (我來自阿根廷) –

+0

Gl ==祝你好運:)。對於使用Mapper的代碼,您必須調整它以使用工廠接口而不是gettonstance by singleton。 – AlexTheo

1

靜態類可以被嘲笑,雖然不知道你用什麼語言/環境,有沒有辦法說有。

我有一個代碼庫,其結果與您所說的完全相同;我們創建了幾十個靜態類的接口和默認實現(不要恐慌 - 代碼生成)。默認impls只是委託給單身人士。使用默認impls

主叫類被切換到DI,但然後更容易測試。與其他靜態類或單例相關的靜態類移至使用默認impls。

你嘲笑單身像任何其他類 - 如果它有一個getInstance(或同等學歷),你可以把它返回任何你想要的。或者你可以走相同的路線並使用DI。

+0

好的,我使用.NET(更新的問題)。輕鬆地嘲諷靜態類是否可能? –

+0

@dario_ramos我不知道,但同行的答案意味着你可以。 –

1

優秀的問題! 您可以通過創建一個新類繼承單類Mapper類來模擬您的Mapper類,然後使用它攔截對數據庫的所有調用。