2013-08-03 54 views
2

對於項目,我使用MEF框架的CompositeContainer類。現在我想做一個單元測試(用moq)來驗證ComposeParts(它是AttributedModelServices中的擴展方法)方法是否被調用。如果調用外部庫的方法,用Moq測試

只是用moq嘲笑它不起作用,因爲該方法不是虛擬的。我發現了一些方法來做到這一點,但他們都讓我改變CompositeContainer類,這是我不能做的。

在moq中是否有方法來測試外部第三方庫的非虛擬方法是否被調用?

在此先感謝您的答覆。

示例代碼:

public void Load(string path, CompositionContainer container) 
{   
    container.ComposeParts(this);   
} 

這裏容器是由MEF庫和ComposeParts在System.ComponentModel.Composition命名空間的擴展方法:

// 
// Summary: 
//  Creates composable parts from an array of attributed objects and composes 
//  them in the specified composition container. 
// 
// Parameters: 
// container: 
//  The composition container to perform composition in. 
// 
// attributedParts: 
//  An array of attributed objects to compose. 
public static void ComposeParts(this CompositionContainer container, params object[] attributedParts); 
+0

你能舉一個你打電話的擴展方法的例子嗎? –

+0

您嘗試測試一個不屬於您的類是否調用某個方法? –

+0

也許你正在測試一段錯誤的代碼,也許你應該測試在你的應用程序中調用這個方法的效果。 –

回答

1

我不認爲可以直接驗證是否使用Moq調用第三方庫方法,但可以檢查調用方法的副作用。由於您正在使用MEF在運行時檢索您的實現,因此我會測試您的類型是否正確加載。所以,如果你有這樣的事情:

public interface IInterfaceToCompose 
{ 
    string MethodToCreate(); 
} 

[Export(typeof(IInterfaceToCompose))] 
public class ConcreteImplementation1 : IInterfaceToCompose 
{ 
    public string MethodToCreate() 
    { 
     return "Implementation 1"; 
    } 
} 

[Export(typeof(IInterfaceToCompose))] 
public class ConcreteImplementation2 : IInterfaceToCompose 
{ 
    public string MethodToCreate() 
    { 
     return "Implementation 2"; 
    } 
} 

然後,您可以編寫一個測試,看起來是這樣的:

[ImportMany(typeof(IInterfaceToCompose))] 
public IInterfaceToCompose ComposedItems { get; set; } 

[Test] 
public void WhenComposingTheComposedItems_ShouldLoadExportedTypes() 
{ 
    Load("testPath", YourContainer); 

    Assert.AreEqual(2, ComposedItems.Count()); 
} 

你真的想測試(IMO)什麼是您創建由類正確,並且它們都可以由MEF CompositionContainer加載。

一個好的第二個測試是做一個初始加載,添加一個dll到第三個實現者,並確保最終的計數是3(你的系統是否動態加載新模塊)。這會捕獲錯誤,比如忘記用Export屬性來賦值新的實現,並且確保你的類在發生變化時正確地獲取變化。

+0

我確實可以使用該功能,看看它是否加載模塊。但後來我在技術上也在測試第三方代碼。我想知道如果沒有它,我能否做到這一點。我唯一需要知道的是:「它是否稱爲方法」。如果該方法有效或不是另一個單元測試(和其他人的關注)。 –

+1

接下來我能想到的最好的方法是使用名爲ComposedParts的方法創建包裝接口ICompositionContainer,並且您可以在生產/集成測試場景中發送模擬測試和真實事件的包裝版本。然後你可以斷言接口方法被調用。雖然這不能證明你的包裝類是正確的,但它將證明一個採用ICompositionContainer類型的接口的對象具有調用的ComposeParts方法(這聽起來像你想要的)。 –

+0

我希望我可以跳過設置一個虛擬模塊來測試該方法,但它似乎是唯一的方法。創建一個包裝器和接口只是將問題轉移到包裝器,並向測試類添加不必要的代碼。所以我會回答這個問題。謝謝您的幫助。 –

0

它在你的類實現Load方法?你有沒有考慮從那裏取出它?考慮到單一責任原則,看起來你的班級做得太多了。

我會建議,你分裂的功能 - 你的類做任何業務邏輯,它需要做的。還有另外一個負責組裝容器的「基礎設施」類 - 在你的情況下獲得你的類的一個實例,並將它註冊到容器中。

你會有幾乎相同的問題,但在另一個地方。而這個「新」地方將更加關注其功能,您可以使用真實的容器對其進行隔離測試,並在合適的部分組成的情況下對其進行檢查。

+0

這完全是你正在描述的實際類,但是因爲我想舉一個簡單的例子,所以我給了這段代碼,以保持清楚。 –

0

如果您只想檢查一個方法被調用,則可以將CompositionContainer包裝在一個名爲ICompositionContainer的包裝器接口中,該接口具有相同的方法簽名。然後用起訂量,你可以斷言,該方法被稱爲:

mock.Verify(cc => cc.ComposeParts(), Times.Once()); 

這裏的缺點是,你正在創建一個接口,隱瞞事實,原來實行未實行一個給你。

的示例代碼現在將是:

public void Load(string path, ICompositionContainer container) 
{   
    container.ComposeParts(this);   
} 

有跡象表明,包裹有問題的測試類在.NET框架如SystemWrapper其他項目的例子。