起订量It.Is <>不匹配

问题描述:

此代码:起订量It.Is <>不匹配

hub.MockedUserRepository.Setup(r => r.Update(It.IsAny<ControllUser>())) 
         .Callback((ControllUser usr) => Console.WriteLine("NULL = " + (usr.Zombies[0].ConnectionId == null))) 
         .Verifiable(); 

将打印

NULL =真

所以我用这个匹配会抓住它想:

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(); 

但它没有。

为什么?

通过查看source code of It,它与表达式树有关。我喜欢这个问题;他们可能会很困惑。如果你想看看下面的方法定义:

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); 
} 

,如果您执行以下行:

var zombieDisconnectParameterMatcher = It.Is<ControllUser>(x => x.Zombies[0].ConnectionId == null); 

然后It.Is<ControllUser>()将尝试呼叫被叫Match.Create<ControllUser>()方法,它返回的默认ControllUser。我假设ControllUser是一类,因此zombieDisconnectParameterMatcher将是null。你应该能够通过调试器看到这一点。那么究竟是什么你打电话是:

hub.MockedUserRepository.Setup(r => r.Update(null)) 
    .Callback((ControllUser usr) => Console.WriteLine("NULL = " + (usr.Zombies[0].ConnectionId == null))) 
    .Verifiable(); 

与执行Update方法当一个非空ControllUser(从正在例如测试的方法),回调就不会触发。它不符合标准,因为它不为空。你也会看到验证失败。

要解决此问题,请嵌入zombieDisconnectParameterMatcher变量,或使其成为表达式类型变量(例如,Expression<Func<...>>)。后者将确保代码不被执行,但被视为模拟框架可以推理的表达式('Update被称为Zombies[0].ConnectionId == null?)。

+0

@Caramiriel先生,我向你敬礼。 – fernandoespinosa 2014-04-07 18:15:16

这取决于如何实例化ControllUser实例。如果您在模拟中引用的实例不是被测代码中提到的实际实例,则Setup将会失败。您需要确保在测试代码中提到的ControllUser的实例是与测试代码中相同的对象。如果不是,您将不得不使用It.IsAny<ControllUser>()和回调进行测试,如第一个示例所示。如果没有看到更多您正在测试的代码,很难确定地说出来。