2010-10-28 234 views
2

所以這是我猜想很多人想要做的事情,嘲笑一個集合。在犀牛過去我喜歡的東西做到了這一點:用犀牛嘲笑嘲笑系列

var col_mock = MockRepository.GenerateMock<ICustomCollection>(); // returns ICustom let's say 
List<ICustom> col_real = new List<ICustom>(); 
col_real.Add(custom_mock1); 
col_real.Add(custom_mock2); 
col_real.Add(custom_mock3); 
col_mock.Stub(x => x.GetEnumerator()).Return(col_real.GetEnumerator()); 

所以燁這工作得很好,當你的foreach col_mock你得到的嘲笑(custom_mock1等)對象回來。大!我們通過使用類型列表來成功地模擬自定義集合,以實際存儲大量模擬對象。

問題是,你只能這樣做一次!你只能對這個集合進行一次foreach。有沒有人知道(沒有創建一個實際的自定義集合...)我如何實現可以迭代多次的自定義集合的模擬?

回答

8

問題是,只有當您調用Return時,枚舉器纔會實例化一次。然後它返回第一個foreach之後已經在列表末尾的相同實例。

您需要在每次調用GetEnumerator時實例化一個新的枚舉器。您可以使用WhenCalled來執行此操作。

Return仍然需要,因爲Rhino Mocks在缺失時會發出抱怨。但是,作爲參數傳遞的並不重要。

[TestMethod] 
public void GetEnumerator() 
{ 
    IList<int> col_mock = MockRepository.GenerateMock<IList<int>>(); 
    List<int> col_real = new List<int>(); 
    col_real.Add(1); 
    col_real.Add(2); 
    col_real.Add(3); 
    col_mock 
     .Stub(x => x.GetEnumerator()) 
     // create new enumerator instance for each call 
     .WhenCalled(call => call.ReturnValue = col_real.GetEnumerator()) 
     .Return(null) // is ignored, but needed for Rhinos validation 
     .Repeat.Any(); 

    foreach (int i in col_mock) 
    { 
    } 

    int count = 0; 
    foreach (int i in col_mock) 
    { 
     count++; 
    } 
    Assert.AreSame(3, count); 
} 
+1

謝謝!並做得很好,實際上Return(null)和Repeat.Any調用似乎不是必需的。我之前沒有使用過WhenCalled,這正是我想要做的。 – MRAH 2010-10-28 14:32:09

4

所以這是我想很多人都想做的事,嘲笑的集合。

其實沒有。模擬的一點是要快速調出一個具有完全控制權的特定界面和行爲的對象,以便您可以鍛鍊您的課堂。

但是在需要ICollection<Foo>的情況下,通常可以創建一個List<Foo>實例。您可以以任何您想要的方式在單元測試中填充列表;你已經完全控制了。

或者假設你需要一個IEnumerable<Foo>帶有更多有趣的行爲,你不能用列表產生一個無限的枚舉或者拋出異常的枚舉。這可以通過在單元測試類中使用yield關鍵字定義迭代器方法來完成。再次,一個模擬是沒有必要的。

+1

我不得不在這裏不同意你的意見。當你的收藏集不是ICollection (或IList 等的衍生物),但實際上是一個你不能改變但必須使用的oldschool自定義集合對象(在我的情況下);那麼你將需要模擬集合對象本身。 自從.NET 1.1以來,我使用的一些接口還沒有被重構。 感謝您的輸入。 – MRAH 2010-10-28 14:35:46