Mocking GetEnumerator() method of an IEnumerable<T> types

381 views
Skip to first unread message

Pat

unread,
Dec 22, 2008, 3:48:37 PM12/22/08
to Rhino.Mocks
Using the AAA style, I have some code that looks like:

// Arrange
Fee1 = Stub<IFee>();
Fee1.Stub(x => x.Total).Return(10);
Fee2 = Stub<IFee>();
Fee2.Stub(x => x.Total).Return(20);

FeeContainer = Stub<IFeeContainer>();
FeeContainer.Stub(x => x.GetEnumerator()).Return(new List<IFee>
{ Fee1, Fee2 }.GetEnumerator());

// Act
SUT.DoSomething(FeeContainer); // does something like foreach(IFee fee
in FeeContainer) {...}

^^^ Do something needs to iterate over each item in the FeeContainer
object, but the inner scope of the foreach loop over FeeContainer is
never reached.

Any ideas?

Ayende Rahien

unread,
Dec 22, 2008, 7:47:33 PM12/22/08
to Rhino...@googlegroups.com
It look like it should work.
can you post a full test case?

Pat

unread,
Dec 23, 2008, 9:56:06 AM12/23/08
to Rhino.Mocks
Blah... I should have written a test case to isolate the issue. The
following snippet is working, which means I must have some other kind
of evil lurking in my test case...

[TestFixture]
public class EnumeratorTest
{
[Test]
public void Should_add_numbers_and_produce_total()
{
var numbers = MockRepository.GenerateStub<INumbers>();

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

var sut = new NumberAdder();
var total = sut.Total(numbers);

Assert.AreEqual(6, total);
}
}

public class NumberAdder
{
public int Total(INumbers numbers)
{
return numbers.Sum();
}
}

public interface INumbers : IEnumerable<int> { }

I will report back if I need more help. Thanks.

On Dec 22, 7:47 pm, "Ayende Rahien" <aye...@ayende.com> wrote:
> It look like it should work.
> can you post a full test case?
>

Pat

unread,
Dec 23, 2008, 3:18:18 PM12/23/08
to Rhino.Mocks
Okay, I've isolated the issue here:

[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> { }

Thanks in advance.

Pat

unread,
Dec 23, 2008, 4:52:57 PM12/23/08
to Rhino.Mocks
I think there is something very subtle about this test case, and I
think it is from me not thinking through how Rhino Mocks stubbing
actually works. Typically, when you enumerate over an IEnumerable, you
are starting with a fresh IEnumerator. In the example above, it looks
like I could be re-using the same enumerator the second time I am
calling sum, and if the enumerator is already at the end of its
sequence, that would explain why the second call to Sum() returns 0.

If this is the case, how could I mock out the GetEnumerator() in such
a way that it behaves in the way that I am wanting it to (e.g. new
enumerator or same enumerator reset to position 0).

Cvetomir Todorov

unread,
Dec 25, 2008, 6:46:53 AM12/25/08
to Rhino...@googlegroups.com
When you create the stub, you may add .Repeat.Times(2);
You can try if that can help you.
--
Software modules coupling is the path to the dark side.
Coupling leads to complexity.
Complexity leads to confusion.
Confusion leads to suffering.
Once you start down the dark path, forever will it dominate your destiny, consume you it will!

Pat

unread,
Dec 30, 2008, 11:25:21 AM12/30/08
to Rhino.Mocks
Well the stub is semantically equivalent to SetupResult.For, which is
Repeat.Any(). The real challenge here is how can I make my stub
dynamically resolve a new enumerator whenever GetEnumerator() is
called. Still not sure on this one.

I guess this is what typemock's Isolator does, I'm just not sure if
rhino mocks has the equivalent capability.

So any reply would be helpful. "yes" or "submit a patch" =)

On Dec 25, 6:46 am, "Cvetomir Todorov"

Ayende Rahien

unread,
Dec 30, 2008, 11:27:32 AM12/30/08
to Rhino...@googlegroups.com
WhenCalled

Pat

unread,
Dec 30, 2008, 12:39:25 PM12/30/08
to Rhino.Mocks
That was it. The test will pass with the following modification:

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

Thanks Orende. =]

On Dec 30, 11:27 am, "Ayende Rahien" <aye...@ayende.com> wrote:
> WhenCalled
>
Reply all
Reply to author
Forward
0 new messages