2009-04-07 80 views
18

我剛切換到Moq並遇到問題。我正在測試一個創建業務對象的新實例的方法,通過用戶輸入值設置對象的屬性並調用一個方法(SaveCustomerContact)來保存新對象。業務對象作爲ref參數傳遞,因爲它通過遠程處理層。我需要測試傳遞給SaveCustomerContact的對象是否按照預期設置了其所有屬性,但是因爲它在控制器方法中實例化爲新的,所以我似乎無法這樣做。使用Moq驗證參考參數的值

public void AddContact() { 

    var contact = new CustomerContact() { CustomerId = m_model.CustomerId }; 

    contact.Name = m_model.CustomerContactName; 
    contact.PhoneNumber = m_model.PhoneNumber; 
    contact.FaxNumber = m_model.FaxNumber; 
    contact.Email = m_model.Email; 
    contact.ReceiveInvoiceFlag = m_model.ReceiveInvoiceFlag; 
    contact.ReceiveStatementFlag = m_model.ReceiveStatementFlag; 
    contact.ReceiveContractFlag = m_model.ReceiveContractFlag; 
    contact.EmailFlag = m_model.EmailFlag; 
    contact.FaxFlag = m_model.FaxFlag; 
    contact.PostalMailFlag = m_model.PostalMailFlag; 
    contact.CustomerLocationId = m_model.CustomerLocationId; 

    RemotingHandler.SaveCustomerContact(ref contact); 
} 

這裏的測試:

[TestMethod()] 
public void AddContactTest() { 

    int customerId = 0; 

    string name = "a"; 

    var actual = new CustomerContact(); 

    var expected = new CustomerContact() { 
     CustomerId = customerId, 
     Name = name 
    }; 

    model.Setup(m => m.CustomerId).Returns(customerId); 
    model.SetupProperty(m => model.CustomerContactName, name); 
    model.SetupProperty(m => m.PhoneNumber, string.Empty); 
    model.SetupProperty(m => m.FaxNumber, string.Empty); 
    model.SetupProperty(m => m.Email, string.Empty); 
    model.SetupProperty(m => m.ReceiveInvoiceFlag, false); 
    model.SetupProperty(m => m.ReceiveStatementFlag, false); 
    model.SetupProperty(m => m.ReceiveContractFlag, false); 
    model.SetupProperty(m => m.EmailFlag, false); 
    model.SetupProperty(m => m.FaxFlag, false); 
    model.SetupProperty(m => m.PostalMailFlag, false); 
    model.SetupProperty(m => m.CustomerLocationId, 0); 

    remote 
     .Setup(r => r.SaveCustomerContact(ref actual)) 
     .Callback(() => Assert.AreEqual(actual, expected)); 

    target.AddContact(); 

} 

這僅僅是最近許多嘗試得到阿霍德該參數的。作爲參考,實際值不會從其初始(構造)狀態改變。

移動目標調用失敗後的Assert.AreEqual(預期的,實際的)。如果我將.Verifiable()添加到設置而不是.CallBack,然後在目標之後調用remote.Verify(或者,我假設將模擬設置爲strict),它總是失敗,因爲我在測試中提供的參數不是與在控制器方法中創建的實例相同的實例。

我正在使用Moq 3.0.308.2。任何想法如何測試這將不勝感激。謝謝!

回答

19

我無法爲您提供一個確切的解決方案,但另一種方法是在適配器後面隱藏pass-by-ref語義,該適配器通過值接收參數並將其轉發給RemotingHandler。這將是更容易嘲笑,並會刪除界面中的「裁判」疣(我一直懷疑ref參數:-))

編輯:

或者你可以使用一個存根,而不是一個模擬的,例如:

public class StubRemotingHandler : IRemotingHandler 
{ 
    public CustomerContact savedContact; 

    public void SaveCustomerContact(ref CustomerContact contact) 
    { 
     savedContact = contact; 
    } 
} 

現在,您可以檢查對象保存在您的測試:

IRemotingHandler remote = new StubRemotingHandler(); 
... 
//pass the stub to your object-under-test 
... 
target.AddContact(); 
Assert.AreEqual(expected, remote.savedContact); 

您也說您的評論:

我討厭開始包裝後端的隨機位的先例,所以我可以更容易地編寫測試

我認爲這是正是你需要的先例!如果你的代碼不可測試,你將繼續努力測試它。讓測試更容易,並增加您的覆蓋範圍。

+0

我想我不確定你會如何存根(儘管我對存根不瞭解太多)。你能詳細說明如何處理? – 2009-04-10 03:26:16

+0

另外,儘管我在ref問題上同意你的意見,但這就是我們的遠程處理層的工作方式,我不願意開始包裝後端隨機位的先例,因此我可以更輕鬆地編寫測試。 – 2009-04-10 03:29:50

9

不幸的是,如果沒有Moq的直接支持,我不確定這是否可能。問題是Lambda表達式不支持ref或out。

「A lambda表達式不能直接捕獲來自的封閉方法ref或輸出參數」

http://msdn.microsoft.com/en-us/library/bb397687.aspx

我甚至不能得到一個例子像您的工作。將ref添加到安裝程序無法編譯。

您可能要檢查出的起訂量爲討論更 http://groups.google.com/group/moqdisc

好運。

+0

很好的答案! :) – Delashmate 2011-11-14 12:15:24

10

最新版本的Moq支持這種情況。

http://code.google.com/p/moq/wiki/QuickStart從快速入門摘自:

// ref arguments 
var instance = new Bar(); 
// Only matches if the ref argument to the invocation is the same instance 
mock.Setup(foo => foo.Submit(ref instance)).Returns(true); 
0

我也遇到過類似的問題。位我通過使用最新的Moq並通過如

var instance = new Bar(); Mock.Setup(foo => foo.Submit(ref instance))。返回(true);

早些時候,我使用的是同樣的方法,但我沒有得到真正的回報。

實際功能實例內部正在創建並覆蓋從單元測試類傳遞的實例導致問題。我刪除了實際類中的實例創建,然後運行。

希望它能幫助你。

謝謝