9

这段代码:

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

将打印

空=真

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

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

但事实并非如此。

为什么?

4

2 回答 2

11

通过查看 的源代码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使用非 null 执行方法时ControllUser(例如来自正在测试的方法),回调将不会触发。它根本不符合条件,因为它不为空。您也会看到验证失败。

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

于 2013-03-12T22:21:18.743 回答
1

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

于 2013-03-12T22:10:19.877 回答