Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Callback with specific object type fails when not after a Return #872

Closed
debslord opened this issue Aug 7, 2019 · 4 comments
Closed

Callback with specific object type fails when not after a Return #872

debslord opened this issue Aug 7, 2019 · 4 comments
Milestone

Comments

@debslord
Copy link

debslord commented Aug 7, 2019

Moq version 4.12.0

Callback for a method with multiple parameters when one is a specific object type throws the following error unless the Callback follows a Returns.

Message: Initialization method Project.Services.Tests.__Initialize threw exception. System.ArgumentException: Invalid callback. Setup on method with parameters (String,Object) cannot invoke callback with parameters (String,SpecficObjectType)..

These setups get the above error:

_mockService
     .Setup(x => x.SomeMethod(fakeString, It.IsAny<SpecficObjectType>()))
     .Callback<string, SpecficObjectType>((a, b) => _parameters = b);

_mockService
     .Setup(x => x.SomeMethod(fakeString, It.IsAny<SpecficObjectType>()))
     .Callback<string, SpecficObjectType>((a, b) => _parameters = b)
     .Returns(() => value);

These setups work:

_mockService
     .Setup(x => x.SomeMethod(fakeString, It.IsAny<SpecficObjectType>()))
     .Returns(() => value)
     .Callback<string, SpecficObjectType>((a, b) => _parameters = b);

_mockService
     .Setup(x => x.SomeMethod(fakeString, It.IsAny<SpecficObjectType>()))
     .Callback<string, object>((a, b) => _parameters = (SpecficObjectType)b)
     .Returns(() => value);
@stakx
Copy link
Contributor

stakx commented Aug 7, 2019

Your callback's parameter types should match the parameter types of the method you're setting up, so some of the errors you're seeing are due to that (i.e. a mistake on your part).

However, this case looks strange:

_mockService
     .Setup(x => x.SomeMethod(fakeString, It.IsAny<SpecficObjectType>()))
     .Returns(() => value)
     .Callback<string, SpecficObjectType>((a, b) => _parameters = b);

I suspect that the above shouldn't work, either.

I'll take a closer look sometime during the next few days.

@stakx
Copy link
Contributor

stakx commented Aug 7, 2019

I am sure that's not what you intended with this issue, but the solution here is to make post-Returns callback delegate validation more strict so we no longer have an inconsistency.

Like I wrote above, if you have a method with parameter list, say, (string, object), you cannot specify a callback delegate with parameter list (string, string) because you'd be coercing the second argument to a type that it might not be compatible with. While the It.IsAny<string>() argument matcher protects against this problem at runtime, it doesn't help a bit at compile time... and reliance on static typing is one of Moq's declared goals.

@stakx stakx closed this as completed Aug 7, 2019
@stakx stakx added this to the 4.13.0 milestone Aug 7, 2019
@debslord
Copy link
Author

debslord commented Aug 8, 2019

I will update my code my side for more consistency. However for your reference please find the following zipped example of the two setups one passes the tests and one does not. If you required an example of the issue.

MoqDemo.zip

@stakx
Copy link
Contributor

stakx commented Aug 8, 2019

If you required an example of the issue.

Thanks.

I've already added these tests to Moq's test suite which cover the same use cases.

But I've quickly run your unit tests against Moq's master, and they now all fail... as they should.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants