C# 当从匿名函数调用.Is…()时,为什么Moq设置/验证匹配器失败

C# 当从匿名函数调用.Is…()时,为什么Moq设置/验证匹配器失败,c#,moq,C#,Moq,当我试图简化创建一个相当复杂的表达式树来设置/验证与moq的匹配时,我遇到了一些奇怪的行为 假设我在模拟下面定义的简单接口 public interface IService { int Send(int value); } 下面的代码表示5个测试。对每个mockSender.Setup(…)进行一次测试。有人能解释为什么标记为失败的测试会失败吗 [Test] public void TestInlineSetup() { const int expected = 5;

当我试图简化创建一个相当复杂的表达式树来设置/验证与moq的匹配时,我遇到了一些奇怪的行为

假设我在模拟下面定义的简单接口

public interface IService
{
    int Send(int value);
}
下面的代码表示5个测试。对每个
mockSender.Setup(…)
进行一次测试。有人能解释为什么标记为失败的测试会失败吗

[Test]
public void TestInlineSetup()
{
    const int expected = 5;
    var mockSender = new Mock<IService>(MockBehavior.Loose);

    //passes
    mockSender.Setup(s => s.Send(It.IsAny<int>())).Returns(expected);

    //fails
    var sendMatch = It.IsAny<int>();
    mockSender.Setup(s => s.Send(sendMatch)).Returns(expected);

    //passes
    mockSender.Setup(s => s.Send(SendMatchFromMethod())).Returns(expected);

    //fails
    var sendMatch = SendMatchFromMethod();
    mockSender.Setup(s => s.Send(sendMatch)).Returns(expected);

    //fails (this is somewhat contrived, but I have reasons for wanting to curry this)
    mockSender.Setup(s => s.Send(SendMatchFromCurriedMethod()())).Returns(expected);

    Assert.That(mockSender.Object.Send(expected), Is.EqualTo(expected));
}

public static int SendMatchFromMethod()
{
    return It.IsAny<int>();
}

public static Func<int> SendMatchFromCurriedMethod()
{
    return () => It.IsAny<int>();
}
[测试]
public void TestInlineSetup()
{
预期常数int=5;
var mockSender=new Mock(MockBehavior.Loose);
//通行证
mockSender.Setup(s=>s.Send(It.IsAny())。返回(预期);
//失败
var sendMatch=It.IsAny();
mockSender.Setup(s=>s.Send(sendMatch))。返回(预期);
//通行证
mockSender.Setup(s=>s.Send(SendMatchFromMethod())。返回(预期);
//失败
var sendMatch=sendmatchfromthod();
mockSender.Setup(s=>s.Send(sendMatch))。返回(预期);
//失败(这有点做作,但我有理由想讨好它)
mockSender.Setup(s=>s.Send(SendMatchFromCurriedMethod())。返回(预期);
Assert.That(mockSender.Object.Send(预期),Is.EqualTo(预期));
}
公共静态int SendMatchFromMethod()
{
返回它。IsAny();
}
公共静态函数SendMatchFromCurriedMethod()
{
return()=>It.IsAny();
}

编辑:我知道Mock.Of(..),通常更喜欢使用它,但在这种情况下,它不是一个选项。

这似乎与我不久前遇到的情况非常相似:

问题似乎在于何时对
It.IsAny()
进行评估。通过了两个测试后,将在
设置(…)
中对其进行评估,效果良好。在前两个失败的测试中,它的评估超出了
设置(…)
的范围,因此无法正确评估。变量中可能存储的是
It.IsAny()
,这将是
int
0
)的默认值


我不知道上次测试失败的确切原因,但可能是因为作为一种优化,您的静态
Func
Setup(…)
执行之前得到评估,也可能是在
Setup(…)
之后得到评估,但无论如何,它都是在
Setup(…)之外发生的

问题源于Moq试图解析提供的表达式树以创建参数匹配器的方式。您可以在此处找到来源:-

关于来源:-

  • It.IsAny
    匹配器是通过编译和执行作为参数传递的表达式并查找任何匹配项来检测的(请参阅)
  • 上述步骤仅对方法调用和成员访问发生
考虑到这一点

  • 第二次测试失败,因为
    It.IsAny
    方法已在matcher工厂外评估。因此,您有一个0的MemberAccess表达式
  • 第三个测试通过,因为
    SendMatchFromMethod
    被视为一个方法调用表达式,并且调用在MatcherFactory内进行计算
  • 第四个测试失败的原因与第二个测试失败的原因相同,该函数已经求值,Moq无法检测到您实际调用了
    It。Is
  • 第五个测试失败,因为表达式被视为函数调用,并且Moq不会对这种类型的表达式执行匹配器检查
  • 老实说,第四个测试应该通过,它似乎只是一个疏忽,它被忽略了,可能只是因为它有点边缘的情况


    最后,
    Match.Create
    MatchAttribute
    可用于处理复杂的谓词,也许它们可能适合您的用例?

    正确,您不能使用它。i设置或验证的lambda表达式的任何外部