为什么使用非内联It.IsAny<;T>;Moq无法正常工作

本文关键字:Moq 常工作 工作 gt It IsAny 为什么 lt | 更新日期: 2023-09-27 18:21:48

It.IsAny<T>()分配给变量以在模拟对象的Setup中使用不会按预期工作:下面显示的测试失败。

但是,如果我内联anyString变量,测试就会通过。这是怎么回事?

public class MyService
{
    private readonly IDependency _dependency;
    public MyService(IDependency dependency)
    {
        _dependency = dependency;
    }
    public string UseTheDependency(string input)
    {
        return _dependency.GetValue(input);
    }
}
public interface IDependency
{
    string GetValue(string input);
}
public class Tests
{
    [Test]
    public void TestTheTestClass()
    {
        var mockDependency = new Mock<IDependency>();
        var anyString = It.IsAny<string>();
        mockDependency.Setup(x => x.GetValue(anyString)).Returns("expected value");
        var service = new MyService(mockDependency.Object);
        var result = service.UseTheDependency("something random");
        Assert.That(result, Is.EqualTo("expected value"));
    }
}

为什么使用非内联It.IsAny<;T>;Moq无法正常工作

这是因为Setup方法将Linq表达式(Expression<Func<IDependency, string>>)作为参数,而不是委托(Func<IDependency, string>)。它允许Moq检查抽象语法树,以了解正在配置的调用。如果您使用在表达式外部声明的变量,Moq不知道您使用了It.IsAny,它只看到了null(从技术上讲,它看到了对封装捕获的局部变量的对象的字段anyString的访问,而该字段只包含null)。

编辑:我很久以前就写了这个答案,现在我意识到它有一部分是错误的。多年来,我一直是FakeIseasy(另一个嘲讽库)的维护者,它使用了类似于Moq的方法,所以现在我对它有了更好的理解…

不应该执行It.IsAny;它执行,并产生一个参数约束。但是,只有当Moq具有该约束的上下文时,才在Setup中评估调用表达式时捕获该约束。如果您只是在对Setup的调用之外调用It.IsAny,当没有上下文时,生成的约束不会被捕获,而是被丢弃。