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

pro*_*mer 12 c# rhino-mocks mocking

以下测试用例在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> { } 
Run Code Online (Sandbox Code Playgroud)

我认为这个测试用例有一些非常微妙的东西,我认为我不是在考虑Rhino Mocks stbing的实际效果.通常,当您枚举IEnumerable时,您将从一个新的IEnumerator开始.在上面的例子中,看起来我可以在第二次调用sum时重新使用相同的枚举器,并且如果枚举器已经在它的序列的末尾,那么这将解释为什么第二次调用Sum()会返回0.如果是这种情况,我怎么能以这样的方式模拟GetEnumerator(),使其表现得像我想要的那样(例如新的枚举器或同一个枚举器重置为0)?

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

pro*_*mer 13

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

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

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

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