简体   繁体   中英

Moq It.Is<> not matching

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?

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 ?').

It depends how the ControllUser instance is instantiated. If the instance that you refer to within the mock is not the actual instance referred to in the code under test, the Setup will fail. You will need to ensure that the instance of ControllUser referred to in the code under test is the same object as the one in the test code. If it isn't, you'll have to test for it using It.IsAny<ControllUser>() and a callback, as your first example shows. It's hard to say with certainty without seeing more of the code that you're testing.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM