You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Extracting (as a variable) the Func<T, bool> part of the expression parameter of It.Is<T> can result in missing setups when performing more than one setup on the same method using the same lambda parameter name.
This is not a shower stopper since there are alternatives to extracting the Func<T, bool> such as extracting the full Expression, using custom Matcher functions or of course using different parameter names as demonstrated. However, extracting the Func<> is one the most obvious and easy way to pass anonymous functions to It.Is when the method body needs more than 1 statement. This can be a fairly common scenario when testing method calls thoroughly, and troubleshooting something like can turn into a huge time sink.
Root cause
A string representation of the expression passed into It.Is is used by Moq to generate an ExpressionKey to store the Setups in a dictionary of method calls. This happens in In method Moq.Interceptor.AddCall(IProxyCall, SetupKind) of https://github.com/moq/moq4/blob/master/Source/Interceptor.cs. Unfortunately the conversion from expression body to a string based key loses reference to the named Func, resulting in both setups having identical keys.
Note: I am nowhere close to having a fix for this unfortunately, as it requires diving deep into the Expression evaluation code, or understanding why the expression body is being transformed/simplified/stringified before building the key in the first place. Hopefully someone with familiarity around this can propose a fix faster.
The text was updated successfully, but these errors were encountered:
Thanks for reporting this, and for the analysis. I have some good news for you: Both of your tests pass in the current develop branch. I tracked this down to #363 / commit b4829ff, which fixed some faulty equality comparison logic in ExpressionKey. This will be in the next Moq release (version >4.7.25), which is probably only a couple of days away now.
If you'd like, feel free to submit a pull request that adds your above two tests and the ITestObject interface not shown as a separate #region 374 with a nested public class Issue374 to UnitTests/Regressions/IssueReportsFixture.cs. I'll be happy to merge them in. Always good to have tests. ;)
Scenario
Extracting (as a variable) the
Func<T, bool>
part of the expression parameter ofIt.Is<T>
can result in missing setups when performing more than one setup on the same method using the same lambda parameter name.Illustration
This passes
This does not pass (returned value is null)
Implications
This is not a shower stopper since there are alternatives to extracting the Func<T, bool> such as extracting the full Expression, using custom Matcher functions or of course using different parameter names as demonstrated. However, extracting the Func<> is one the most obvious and easy way to pass anonymous functions to It.Is when the method body needs more than 1 statement. This can be a fairly common scenario when testing method calls thoroughly, and troubleshooting something like can turn into a huge time sink.
Root cause
A string representation of the expression passed into It.Is is used by Moq to generate an ExpressionKey to store the Setups in a dictionary of method calls. This happens in In method
Moq.Interceptor.AddCall(IProxyCall, SetupKind)
of https://github.com/moq/moq4/blob/master/Source/Interceptor.cs. Unfortunately the conversion from expression body to a string based key loses reference to the named Func, resulting in both setups having identical keys.I have included a full repro class + more comments/details in this gist: https://gist.github.com/Aerendel/2ead83066408764b954a74bf4f1c71e1
Note: I am nowhere close to having a fix for this unfortunately, as it requires diving deep into the Expression evaluation code, or understanding why the expression body is being transformed/simplified/stringified before building the key in the first place. Hopefully someone with familiarity around this can propose a fix faster.
The text was updated successfully, but these errors were encountered: