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

时间:2008-12-24 13:36:03

标签: c# mocking rhino-mocks

以下测试用例在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 个答案:

答案 0 :(得分:13)

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

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

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

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

答案 1 :(得分: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>()函数一样。

答案 2 :(得分:0)

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