【问题标题】:Mocking GetEnumerator() method of an IEnumerable<T> types模拟 IEnumerable<T> 类型的 GetEnumerator() 方法
【发布时间】:2008-12-24 13:36:02
【问题描述】:

以下测试用例在 rhino mocks 中失败:

[TestFixture] 
    public class EnumeratorTest 
    { 
        [Test] 
        public void Should_be_able_to_use_enumerator_more_than_once() 
        { 
            var numbers = MockRepository.GenerateStub<INumbers>(); 
            numbers.Stub(x => x.GetEnumerator()).Return(new List<int> 
{ 1, 2, 3 }.GetEnumerator()); 
            var sut = new ObjectThatUsesEnumerator(); 
            var correctResult = sut.DoSomethingOverEnumerator2Times 
(numbers); 
            Assert.IsTrue(correctResult); 
        } 
    } 
    public class ObjectThatUsesEnumerator 
    { 
        public bool DoSomethingOverEnumerator2Times(INumbers numbers) 
        { 
            int sum1 = numbers.Sum(); // returns 6 
            int sum2 = numbers.Sum(); // returns 0 =[ 
            return sum1 + sum2 == sum1 * 2; 
        } 
    } 
    public interface INumbers : IEnumerable<int> { } 

我认为这个测试用例有一些非常微妙的地方,我 认为这是我没有考虑过 Rhino Mocks 存根的原因 确实有效。通常,当您枚举一个 IEnumerable 时,您 从一个新的 IEnumerator 开始。在上面的例子中,它看起来 就像我第二次可以重复使用同一个枚举器 调用 sum,如果枚举数已经在其末尾 序列,这可以解释为什么第二次调用 Sum() 返回 0。 如果是这种情况,我怎么能在这种情况下模拟 GetEnumerator() 它以我想要的方式运行的方式(例如新的 枚举器或相同的枚举器重置到位置 0)?

您将如何修改上述测试用例,以使第二个 .Sum() 调用实际上返回 6 而不是 0?

【问题讨论】:

    标签: c# mocking rhino-mocks


    【解决方案1】:

    WhenCalled() api 允许您动态解析返回值。

    将测试用例更改为以下将允许它通过:

    numbers.Stub(x => x.GetEnumerator())
                         .Return(null)
                         .WhenCalled(x => x.ReturnValue = 
                                        new List<int> { 1, 2, 3 }.GetEnumerator()
                                     );
    

    因此,存根行为将始终返回一个新的枚举器,而不是返回相同的枚举器。

    【讨论】:

      【解决方案2】:

      声明

      numbers.Stub(x => x.GetEnumerator()).Return(new List<int> { 1, 2, 3 }.GetEnumerator());
      

      等同于

      var enumerator = new List<int> { 1, 2, 3 }.GetEnumerator();
      numbers.Stub(x => x.GetEnumerator()).Return(enumerator);
      

      在您的测试中,您告诉 Rhino Mocks 提供相同的 IEnumerator&lt;int&gt; 实例 enumerator 两次。那不是你想要的。 IEnumerator&lt;int&gt; 的单个实例仅适用于一个枚举,而不适用于两个枚举(通常不支持Reset())。您希望 Rhino Mocks 提供两个不同的 IEnumerator&lt;int&gt; 实例,以便它们可以分别求和,就像对任何其他 GetEnumerator&lt;int&gt;() 函数的调用一样。

      【讨论】:

      • 是的,这就是问题所在。问题是如何模拟对单个 IEnumerable 对象的所有调用,以便可以根据需要多次枚举该对象。 >>您将如何修改上述测试用例以使第二个 .Sum() 调用实际上返回 6 而不是 0?不过谢谢!
      【解决方案3】:

      免责声明:我在 Typemock 工作

      我不知道您是否可以使用 Rhino 来执行此操作,但您可以将 Isolator 与 AAA API 一起使用,这正是您正在寻找的 -

      [Test] 
      public void Should_be_able_to_use_enumerator_more_than_once() 
      {
         var numbers = Isolate.Fake.Instance<INumbers>();
         Isolate.WhenCalled(() => numbers).WillReturnCollectionValuesOf(new List<int>{ 1, 2, 3 });
         var sut = new ObjectThatUsesEnumerator(); 
         var correctResult = sut.DoSomethingOverEnumerator2Times(numbers); 
         Assert.IsTrue(correctResult); 
      }
      

      有关详细信息,请参阅开发人员指南中的 Managing Collections

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-08-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-09-23
        • 1970-01-01
        相关资源
        最近更新 更多