此代码:
hub.MockedUserRepository.Setup(r => r.Update(It.IsAny<ControllUser>()))
.Callback((ControllUser usr) => Console.WriteLine("NULL = " + (usr.Zombies[0].ConnectionId == null)))
.Verifiable();
将打印
NULL = True
所以我想使用这种匹配会抓住它:
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();
但事实并非如此。
为什么?
答案 0 :(得分:9)
通过查看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
调用?')。
答案 1 :(得分:1)
这取决于ControllUser
实例的实例化方式。如果您在模拟中引用的实例不是被测试代码中引用的实际实例,则Setup
将失败。您需要确保测试代码中引用的ControllUser
实例与测试代码中的相同的对象。如果不是,则必须使用It.IsAny<ControllUser>()
和回调进行测试,如第一个示例所示。如果没有看到你正在测试的更多代码,很难肯定地说。