2010-10-28 198 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