I ran into some strange behavior when attempting to simplify the creation of a rather complex expression tree for Setup/Verify matching with moq.
Assume I am mocking the simple interface defined below
public interface IService
{
int Send(int value);
}
The following code represents 5 tests. One test for each of the mockSender.Setup(...)
. Can anyone explain why the tests marked as failing do fail?
[Test]
public void TestInlineSetup()
{
const int expected = 5;
var mockSender = new Mock<IService>(MockBehavior.Loose);
//passes
mockSender.Setup(s => s.Send(It.IsAny<int>())).Returns(expected);
//fails
var sendMatch = It.IsAny<int>();
mockSender.Setup(s => s.Send(sendMatch)).Returns(expected);
//passes
mockSender.Setup(s => s.Send(SendMatchFromMethod())).Returns(expected);
//fails
var sendMatch = SendMatchFromMethod();
mockSender.Setup(s => s.Send(sendMatch)).Returns(expected);
//fails (this is somewhat contrived, but I have reasons for wanting to curry this)
mockSender.Setup(s => s.Send(SendMatchFromCurriedMethod()())).Returns(expected);
Assert.That(mockSender.Object.Send(expected), Is.EqualTo(expected));
}
public static int SendMatchFromMethod()
{
return It.IsAny<int>();
}
public static Func<int> SendMatchFromCurriedMethod()
{
return () => It.IsAny<int>();
}
Edit: I know about Mock.Of<..>(..) and normally prefer to use it but in this case it is not an option.
The problem stems from the way Moq tries to parse the supplied expression tree to create a parameter matcher. You can find the source here:-
http://code.google.com/p/moq/source/browse/trunk/Source/MatcherFactory.cs
Referring to the source:-
It.IsAny<int>
matchers are detected by compiling and executing the expression that is passed as the parameter and looking for any matches (see here).So with that in mind....
It.IsAny<int>
method has been evaluated outside of the matcher factory. As such you have a MemberAccess expression to 0.SendMatchFromMethod
is treated as a method call expression and the call is evaluated inside the MatcherFactory.It.Is<Any>
The fourth test, to be honest, should pass and it just seems an oversight that its been left off, probably just because it's a bit of an edge case.
Finally Match.Create<T>
or MatchAttribute
can be used to deal with complex predicates, perhaps they might fit your use case?
This seems to be very similar to a situation I ran into a while ago: Moq unit test with It.IsAny<DateTime>() fails
The issue seems to be with when It.IsAny<int>()
gets evaluated. With the 2 tests that pass, it's getting evaluated inside of Setup(...)
, which works fine. In the first 2 tests that fail, it's getting evaluated outside the scope of Setup(...)
, so it fails to evaluate correctly. What's probably getting stored in your variable is the result of It.IsAny<int>()
, which will be the default value for an int
(0
).
I don't know the exact reason why the last test would fail, but it could be either that as an optimization your static Func<int>
gets evaluated before Setup(...)
executes, or it could be that it gets evaluated after Setup(...)
, but either way it's happening outside of Setup(...)
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With