模拟一个 IEnumerable<T> 类型的 GetEnumerator() 方法

12
以下测试用例在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?

3个回答

13

WhenCalled()接口允许您动态地解析返回值。

将测试用例更改为以下内容将使其通过:

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

因此,代替返回相同的枚举器,存根行为将始终返回新的枚举器。


3
声明
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<int>实例enumerator两次。这不是你想要的。单个IEnumerator<int>实例仅适用于一次枚举,而不是两次枚举(通常不支持Reset())。你希望Rhino Mocks提供两个不同的IEnumerator<int>实例,以便它们可以分别求和,就像对任何其他GetEnumerator<int>()函数的调用一样。

是的,这就是问题所在。问题是如何模拟对单个IEnumerable<T>对象的所有调用,以便我可以枚举该对象多次。
您将如何修改上面的测试用例,以便第二个.Sum()调用实际返回6而不是0?
谢谢!
- programmer

1

免责声明:我在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); 
}

更多信息请参见开发者指南中的管理集合


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接