Friday, April 1, 2011

Invalid callback. Setup on method with parameters ({0}) cannot invoke callback with parameters ({1}).

 

Alright, I have to admit, I am not that well versed in using Moq and am in the process of figuring this out myself. Also there seems to be not a lot of documentation around it.

So while mocking up an object for an interface which looked like this

public interface ICustomerServiceProxy
{
void GetCustomers(Action,Exception> callback);
void SaveCustomers(IEnumerable Customers,Action callback);
}

I wrote some code like this

// Always retrun true on an add mock.
Setup(foo => foo.SaveCustomers(It.IsAny>(), It.IsAny>())) .Callback((Action act) => act(true))

What it is supposed to do is to call my callback with a true return regardless. Even though the code compiled when I run it it gave me the error

Invalid callback. Setup on method with parameters (IEnumerable`1,Action`1) cannot invoke callback with parameters (Action`1).

After digging around I found the issue. If you take a look at the source file at this location you will find that this error is being thrown by SetCallbackWithArguments function which is also illustrated by the stack trace given below.

   at Moq.MethodCall.ThrowParameterMismatch(ParameterInfo[] expected, ParameterInfo[] actual)
at Moq.MethodCall.SetCallbackWithArguments(Delegate callback)
at Moq.MethodCall.Callback[T](Action`1 callback)
at SilverlightLearning.Data.Moq.CustomerServiceProxy..ctor()

If we look at the code in the SetCallbackWithArguments method we see that the exception is thrown only in two cases:



  1. The length of the parameter list in the callback method is equal to the length of parameter list in the original method that was setup.
  2. The parameters should be assignable. i.e. the parameter in the original method at any given index should be assignable to the parameter in the callback method at the same index,

Well then I got it. I had the issue since I did not have the same number of arguments as the method I had setup. Even though I did not need it. So I changed my code to this

mock.Setup(foo => foo.SaveCustomers(It.IsAny>(), It.IsAny>()))
.Callback((IEnumerable List, Action act) => act(true));

And it worked.


So just make sure that the above two rules are followed while setting up the callback and you should be fine.

2 comments:

  1. Thanks! This helped me figure out a similar mysterious error when setting up a callback.

    ReplyDelete