2012-06-26 193 views
3

我知道一個類似的問題已被問到,但我還沒有找到明確的解決方案。我試圖嘲笑一個大班的私人領域。私人領域得到實例在一些較早的方法,我試圖單元測試引用該領域的後一種方法。嘲笑私人領域

所以我有一個較早的方法在我的課:

public bool validateAll(ref DataEntry[] oEntries, string sMediaPlanId, ITemplateGenerator oTempGen) 
{ 
    ... 
    // private field that I am trying to mock 
    this._sMediaPlanObjective = (MPWrapper.Instance).getMediaPlanObjective(sMediaPlanId); 
    ... 
} 

我試圖單元測試引用私有字段的方法:

public bool validateFlightObjective(ref MPDataEntry oEntry) 
{ 
    ... 
    string entryFlightObjective = oEntry.getFlightObjective(); 
    string mediaPlanObjective = this._sMediaPlanObjective; 

    if (entryFlightObjective != mediaPlanObjective) 
    { 
    return false; 
    } 
    ... 

    return true;  
} 

假設我有一個大類,這只是我想測試的一種方法,有沒有可能的方法來模擬這個私人領域?我缺少一些基本的東西,還是應該考慮其他方法?

+0

正如答案中所述,您可以(應該)通過一些重構努力來避免這種情況。如果你仍然不想這樣做,你可以嘗試一個更強大的模擬框架,如Typemock Isolator或者Moles。 – seldary

回答

4

你不能模擬什麼這是私人的,靜態的,或基本上 - 不可重寫(這是作爲免費的嘲諷庫limitation)。

你通常在這種情況下做什麼(當它出現的是private成員進行測試),被提取的private成員到一個單獨的類,並inject它來測試類的依賴。

在你的情況,你確實需要提取創建_sMediaPlanObjective,這是這行代碼:

this._sMediaPlanObjective = 
    (MPWrapper.Instance).getMediaPlanObjective(sMediaPlanId); 

對象,它提供getMediaPlanObjective方法應注射到你的測試類。如果你這樣做,你可以簡單地嘲笑這個對象,並告訴它返回_sMediaPlanObjective的模擬版本。

+0

這是否意味着必須調用validateAll()來設置私有成員的模擬版本,以便我可以測試validateFlightObjective()?或者,讓一些公共/受保護的訪問者設置私人成員是更好的做法。 –

+0

@SamuelHeaney:最有可能的。如果賦予私有字段在'validateAll'方法中完成* only *(並且不能在其他地方完成,那麼在構造函數中,一旦注入了依賴關係),則需要調用它來設置模擬。僅爲單元測試而添加額外的訪問者應該是**最後的手段**。 –

0

沒有理由在private字段上進行任何類型的測試。

使用一個對象可以引用public方法作爲對象的API。 對象本身可以根據您對其執行的操作改變其狀態 - 但它會反映在其他方法/訪問DAL(DB/Registry/File /任何其他不在內存中的資源)中的方法

所以你的情況,你可以有一個單元測試這樣的:

通話,你期望它初始化私有字段的方法和 -

  • 呼叫validateFlightObjective,你知道有一個參數根據_sMediaPlanObjective返回false「通緝成爲國家「,並確認結果是錯誤的。

  • 調用validateFlightObjective帶有一個參數,您知道必須根據_sMediaPlanObjective「想成爲狀態」返回true,並驗證結果是否爲真。

如果你看到它是很難測試這個對象,那麼這可能是一個「嗅覺」 - 也許你有一個以上的責任那裏,你應該開始重構和階級分裂,小班這將更容易測試

這有點長,但我希望這是有益的

+0

我不想測試私人領域本身。不調用初始化私有字段的方法違反了單元測試中行爲的隔離?而且,調用它意味着需要調用其他幾個需要順序調用並訪問數據庫的方法。 –

0

可以使用JustMock框架。 例如:

double value = 0; 
var fakeFilterSetHelper = Mock.Create<FilterSetHelper>(Behavior.CallOriginal); 
Mock.NonPublic.Arrange<double>(fakeFilterSetHelper, memberName: "GetPriceRangeFromSession").Returns(value);