-
-
Notifications
You must be signed in to change notification settings - Fork 794
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
GetHashCode() issues when called from inside constructor of mocked class #1156
Comments
Thanks for reporting. I'll look into it soon.
I suspect this is related to the way how Moq reconstructs a LINQ expression tree ( I'm assuming that the newer reconstrucrion method (the one using a separate proxy) sees the recorded call to More analysis is needed but the problem will likely lie in that direction.
P.S. regardless of whether this can be fixed or not, your code is operating in the intersection of three areas that Moq 4 doesn't (sometimes cannot) support perfectly:
I could go into each of these points further, let it suffice for the moment to say that if you can move your test code away from any of these points (mock interfaces instead; or don't trigger virtual calls from the ctor; or don't setup assignments if not needed) you'll generally be heading into better-supported territory. |
Thanks for your quick response. We have worked around the issue for now by removing the mock on the get/set of this property so we can upgrade to 4.16.1. This did mean we had to replace VerifySet to check the value as well as how many times the setter was called with an Assert.AreEqual. If this is solvable in the Moq library it would be good to revert this change in the future. |
@AP-Maptek, I've taken a closer look, and like I suspected, the problem lies in the LINQ expression tree reconstruction machinery. Your particular issue could be fixed (details on that follow further down), but in the meantime, if you don't mind using an -example.SetupSet(x => x.Title = It.IsAny<string>());
+example.SetupSet(x => x.Title); This will work because that second You can stop reading here, unless you're interested in some technical details about Moq internals. The problem indeed lies in Your code could be got to work by special-casing else if (returnType.IsMockable())
{
this.returnValue = CreateProxy(returnType, null, this.matcherObserver, out _);
}
+else if (invocation.Method.DeclaringType == typeof(object))
+{
+ this.returnValue = returnType.GetDefaultValue();
+}
else
{
throw new NotSupportedException(Resources.LastMemberHasNonInterceptableReturnType);
} It's been a while since I implemented This maybe needs some more thought. |
Ah yes you are right, using that obsolete We have ended up changing the test to call the get/set directly instead of mocking and just checking the expected value rather than also the number of times the setter is expected to be called so we can upgrade to the latest released Moq version. |
(Update: The following probably won't work because there might not be any
Given that you've got a workaround, I'm opting to close this issue. Like I wrote above, the current tree reconstruction logic will probably always have limitations like the one reported here, and it's perhaps more honest to just acknowledge the overall limitations than fixing certain special cases. |
I was upgrading Moq on some test fixtures and found an odd suddenly failing test which I have created a minimal reproducible scenario below.
The following works in Moq 4.10.0 and earlier, but is broken in Moq 4.11.0 and newer including latest at time of writing 4.16.1.
The error message given is:
Message: Test method MoqTest.UnitTest1.TestMethod1 threw exception:
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.NotSupportedException: The return type of the last member shown above is not mockable.
With stack trace:
Any thoughts on why this has changed? Is there a work around?
I suspect other System.Object methods could have issues as well.
The text was updated successfully, but these errors were encountered: