Grzenio
Grzenio

Reputation: 36679

Moq expectations on the same method call with different arguments

I am trying to set up a mock object in a loop that will return different values for a function call with different arguments:

var myMock= new Mock<IInterface>();
for (int i = 0; i < fromKeys.Count; ++i)
{
    var value= new[] {new[] {1.0 + i}};
    _values.Add(value);
    myMock.Setup(x => x.Provide(fromKeys[i])).Returns(new Sth(fromKeys[i], value));
}
_myObject = myMock.Object;

but it crashes when I am calling Provide with the first key in the production code (and not during test setup):

System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation.
  ----> System.ArgumentOutOfRangeException : Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
   at System.RuntimeMethodHandle._InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, ref SignatureStruct sig, MethodAttributes methodAttributes, RuntimeType typeOwner)
   at System.RuntimeMethodHandle.InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeType typeOwner)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
   at System.Delegate.DynamicInvokeImpl(Object[] args)
   at Moq.Evaluator.SubtreeEvaluator.Evaluate(Expression e)
   at Moq.Matchers.LazyEvalMatcher.Matches(Object value)
   at Moq.MethodCall.Matches(ICallContext call)
   at System.Linq.Enumerable.LastOrDefault(IEnumerable`1 source, Func`2 predicate)
   at Moq.ExtractProxyCall.HandleIntercept(ICallContext invocation, InterceptStrategyContext ctx)
   at Moq.Interceptor.Intercept(ICallContext invocation)
   at Castle.DynamicProxy.AbstractInvocation.Proceed()
   at Castle.Proxies.IBrownianProviderProxy.Provide(BrowniansKey keys)
   at MyCode.....

How can I set it up?

Upvotes: 1

Views: 1889

Answers (1)

Ben Allred
Ben Allred

Reputation: 4864

This is a closure problem. x => x.Provide(fromKeys[i]) isn't evaluated until later. By the time it's evaluated later, i == fromKeys.Count, which is out of bounds of the array. If that doesn't make sense, I suggest reading more about closure. The easy solution, though, is to add a line so your code looks like this (in the for loop)

for (int i = 0; i < fromKeys.Count; ++i)
{
    int j = i;
    myMock.Setup(x => x.Provide(fromKeys[j])).Returns(new Sth(fromKeys[j], _values[j]));
}

Upvotes: 7

Related Questions