2008-08-07 50 views
5

我最近在嘲讽中遇到的灾难并不值得一提,我需要实际推送IEnumerable<T>模拟对象中的结果。你如何正确地模拟IEnumerable <T>?

下面是一个示例(示范只有IEnumerable<T>,实际上并不好基于交互的测试!):

using System; 
using System.Collections.Generic; 
using Rhino.Mocks; 
using MbUnit.Framework; 

[TestFixture] 
public class ZooTest 
{ 
    [Test] 
    public void ZooCagesAnimals() 
    { 
     MockRepository mockery = new MockRepository(); 

     IZoo zoo = new Zoo(); 

     // This is the part that feels wrong to create. 
     IList<IAnimal> mockResults = mockery.DynamicMock<IList<IAnimal>>(); 
     IAnimal mockLion = mockery.DynamicMock<IAnimal>(); 
     IAnimal mockRhino = mockery.DynamicMock<IAnimal>(); 

     using (mockery.Record()) 
     { 
      Expect.Call(zoo.Animals) 
       .Return(mockResults) 
       .Repeat.Once(); 
     } 

     using (mockery.Playback()) 
     { 
      zoo.CageThe(mockLion); 
      zoo.CageThe(mockRhino); 

      Assert.AreEqual(mockResults, new List<IAnimal>(zoo.Animals)); 
     }  
    } 
} 


public class Zoo : IZoo 
{ 
    private IList<IAnimal> animals = new List<IAnimal>(); 

    public void CageThe(IAnimal animal) 
    { 
     animals.Add(animal); 
    } 

    public IEnumerable<IAnimal> Animals 
    { 
     get 
     { 
      foreach(IAnimal animal in animals) 
      { 
       yield return animal; 
      } 
     } 
    } 
} 

public interface IAnimal 
{ 
} 

public interface IZoo 
{ 
    IEnumerable<IAnimal> Animals { get;} 
    void CageThe(IAnimal animal); 
} 

我不喜欢我怎么得到它,原因如下工作:

  • 消费IEnumerable<IAnimal>结果到IList<IAnimal> - 因为我知道这将结果检查到堆。
  • 设置结果的内容 - 我也了解;但我的主要观点是测试Zoo.Animals是返回IEnumerable<IAnimal>,甚至更好,它是使用yield return里面。

有关这样做更好或更简单的建议吗?

编辑:我试图确定测试IEnumerable<T>和我正在使用的任何之间的交互的最佳方式。我并非试图测试Zoo可以容纳动物,而是Zoo公开为IEnumerable<IAnimal>,并且也被使用。

+1

回想起来,这是一个** TERRIBLE **问题。试图让选票关闭 – 2009-10-31 05:24:54

回答

4

如果你正在测试实现,你为什么试图嘲笑它呢?为什么不只是CageThe(IAnimal),然后检查动物是否包含该IAnimal?

我得知你在嘲笑IAnimals,看起来你显然还没有任何具体的动物可以玩,但为什么不把它们作为存根呢,因为显然你并不期望别的什么事发生他们除了被列入名单?

编辑:大概的东西沿着这些线路(未测试,可能无法编译,可以吃你的狗等):

[TestFixture] 
public class ZooTest 
{ 
    [Test] 
    public void ZooCagesAnimals() 
    { 
     MockRepository mockery = new MockRepository(); 

     IAnimal mockLion = mockery.Stub<IAnimal>(); 
     IAnimal mockRhino = mockery.Stub<IAnimal>(); 

     IZoo zoo = new Zoo(); 

     zoo.CageThe(mockLion); 
     zoo.CageThe(mockRhino); 

     List<IAnimal> animals = new List<IAnimal>(zoo.Animals); 
     Assert.IsTrue(animals.Contains(mockLion)); 
     Assert.IsTrue(animals.Contains(mockRhino)); 
    } 
} 
3

我不太看你怎么指望上设置的模拟期望一个不是模拟开始的对象。此外,您正在设置返回IList的期望,这在编译器生成迭代器时并不真正发生。

如果你想专门测试迭代器,你应该

Assert.IsNotNull(zoo.Animals); 

然后验证枚举枚举实际上在所有你加入到动物园的事。这是我去那里的原因。 :)

我不确定是否有可能测试yield yield是否被调用,因为yield return仅仅是编译器生成的IEnumerable的语法糖。例如,拨打

zoo.Animals.GetEnumerator(); 

将不会执行您在枚举器中编写的任何代码。第一次发生的是第一次调用IEnumerator。的MoveNext();

现在,如果您尝试测试具体Zoo和该Zoo所包含的IEnumerable之间的交互,则应该在Zoo上创建一个IEnumerable字段,并向该字段注入一个模拟IEnumerable,而不是实现具体的IEnumerable直接在动物园里。

我希望这是一些帮助。

相关问题