Why does the Moq setup / verify matcher fail when It.Is ... () is called from an anonymous function

I came across some weird behavior when trying to simplify the creation of a rather complex expression tree for installing / checking compliance using moq.

Suppose I mock the simple interface defined below

public interface IService { int Send(int value); } 

The following code is 5 tests. One test for each of mockSender.Setup(...) . Can someone explain why the tests marked as unsuccessful will not work?

 [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 usually prefer to use it, but in this case this is not an option.

+4
source share
2 answers

The problem is how Moq tries to parse the provided expression tree to create parameter mappings. 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> detected by compiling and executing an expression that is passed as a parameter and looks for any matches (see here ).
  • The above step is performed only for method calls and member access.

So, bearing in mind ...

  • The second test failed because the It.IsAny<int> method was evaluated outside the factory matches. Therefore, the expression MemberAccess has a value of 0.
  • The third test passes because SendMatchFromMethod treated as an expression of a method call, and the call is evaluated inside the MatcherFactory.
  • The fourth test fails for the same reason as the second, the function has already been evaluated, and Moq cannot detect that you really called It.Is<Any>
  • The fifth test fails because the expression is treated as a function call, and Moq does not perform conformance checking for this type of expression.

The fourth test, to be honest, has to pass, and it just seems like an oversight that it was left, probably only because it is a bit of regional business.

Finally, Match.Create<T> or MatchAttribute can be used to handle complex predicates, maybe they can fit your use case?

+4
source

This is similar to the situation I encountered a while ago: Moq unit test with It.IsAny <DateTime> () fails

The problem seems to be related to the evaluation of It.IsAny<int>() . With two missed tests, it is evaluated inside Setup(...) , which works great. In the first 2 tests that fail, it gets a score outside of Setup(...) , so it cannot correctly evaluate. It is likely that you are storing the result of It.IsAny<int>() in your variable, which will be the default value for int ( 0 ).

I don’t know the exact reason why the last test failed, but it can either be the optimization that the static Func<int> gets evaluated before Setup(...) is executed, or it can be that it gets the rating after Setup(...) , but in any case, this happens outside of Setup(...) .

+3
source

All Articles