12

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

[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?

4

3 回答 3

13

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

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

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

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

于 2008-12-30T17:40:58.923 回答
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>()函数的调用一样。

于 2008-12-24T20:15:40.257 回答
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); 
}

有关详细信息,请参阅开发人员指南中的管理集合

于 2008-12-24T14:44:15.370 回答