Moq It.Is<> not matching
c#, mocking, moq, unit-testing
Solution
By looking at the source code of `It`, it has to do with expression trees. I like the question; they can be quite puzzling. If you would take a look at the following method definitions:
public static TValue It.Is<TValue>(Expression<Func<TValue, bool>> match)
{
return Match<TValue>.Create(
value => match.Compile().Invoke(value),
() => It.Is<TValue>(match));
}
public static T Match.Create<T>(Predicate<T> condition, Expression<Func<T>> renderExpression)
{
// ...
return default(T);
}
If you would execute the following line:
var zombieDisconnectParameterMatcher = It.Is<ControllUser>(x => x.Zombies[0].ConnectionId == null);
Then `It.Is<ControllUser>()` will try to call a method called `Match.Create<ControllUser>()`, which returns the default of `ControllUser`. I assume `ControllUser` is a class and therefore `zombieDisconnectParameterMatcher` will be `null`. You should be able to see this with the debugger. So what actually you're calling is:
hub.MockedUserRepository.Setup(r => r.Update(null))
.Callback((ControllUser usr) => Console.WriteLine("NULL = " + (usr.Zombies[0].ConnectionId == null)))
.Verifiable();
When executing the `Update` method with a non-null `ControllUser` (from the method that is being tested for example), the callback will not trigger. It simply doesn't match the criteria since it's not null. You would see the verification fail, also.
To resolve this issue, either inline the `zombieDisconnectParameterMatcher` variable, or make it an expression typed variable (eg. `Expression<Func<...>>`). The latter will make sure that the code is not executed, but treated as an expression which the mock framework can reason about ('is `Update` being called with `Zombies[0].ConnectionId == null`?').
Problem
This code: ``` hub.MockedUserRepository.Setup(r => r.Update(It.IsAny<ControllUser>())) .Callback((ControllUser usr) => Console.WriteLine("NULL = " + (usr.Zombies[0].ConnectionId == null))) .Verifiable(); ``` Will print NULL = True So i am thinking using this matching will catch it: ``` var zombieDisconnectParameterMatcher = It.Is<ControllUser>(x => x.Zombies[0].ConnectionId == null); hub.MockedUserRepository.Setup(r => r.Update(zombieDisconnectParameterMatcher)) .Callback((ControllUser usr) => Console.WriteLine("NULL = " + (usr.Zombies[0].ConnectionId == null))) .Verifiable(); ``` But it does not. Why?