I have a situation where I have an interface that exposes a method returning an IEnumerable
interface IIEnumerableProvider<T>
{
IEnumerable<T> GetData();
}
I need to be able to create a stub of this that supports being called once, and when the resulting RangeIterator is enumerated a first time returns values defined by the stub, if enumerated a second time it will return a different set of values and so on for further enumerations.
Stubbing for a single enumeration is easy enough:
var stub = MockRepository.GenerateStub<IIEnumerableProvider<int>>();
stub.Stub(x => x.GetData()).Return(new []{1,2,3,4}).Repeat.Once();
Yet this does not cover the scenario where repeated enumerations of the result give different sets of values.
To give context I have a consumer method that calls the GetData method on the provider and uses the returned values twice, in error I enumerated the return twice, with unexpected behavior, but this was not highlighted in my unit tests on the consumer. As very simple consumer implementation to represent what I mean can be shown as:
class Consumer<T>
{
bool UseProvider(IIEnumerableProvider<T> provider)
{
var rangeIterator = provider.GetData();
var firstEnumeration = rangeIterator.ToArray();
var secondEnumeration = rangeIterator.ToArray();
return firstEnumeration.SequenceEquals(secondEnumeration);
}
}
you would expect this to return false if the provider returned a value that is different every time it is enumerated, which is the case if we have a simple concrete implementation of IIEnumerableProvider:
public class RandomIntIEnumerableProvider : IIEnumerableProvider<int>
{
private Random r = new Random();
public IEnumerable<int> GetData()
{
return Enumerable.Range(0,10).Select(x => r.Next());
}
}
So the question is how do I stub the provider in such a way as to produce well defined values on the first enumeration of the rangeIterator, but different (either defined as a list of sets of values or randomly determined). I need this in order to inject it into the consumer and ensure that the consumer is not performing multiple enumeration on the rangeIterator where it is a wrong to do so?
The naive approach of stubbing two return vales from the method does not work:
var stub = MockRepository.GenerateStub<IIEnumerableProvider<int>>();
stub.Stub(x => x.GetData()).Return(new []{1,2,3,4}).Repeat.Once();
stub.Stub(x => x.GetData()).Return(new []{5,6,7,8}).Repeat.Once();
as the GetData method is only called once, the set 1,2,3,4 is seen in the first and second enumerations.