代码之家  ›  专栏  ›  技术社区  ›  Jeremy Holovacs

moq-verify方法签名可以看到调用,但不匹配?

  •  0
  • Jeremy Holovacs  · 技术社区  · 6 年前

    我有一个这样的界面:

    public interface IStatisticsCollector : IDisposable
    {
        Task Measure(string metricName, decimal value, IDictionary<string, string> tags = null);
    }
    

    我正在注射这个 IStatisticsCollector 到我的课堂上,像这样使用它:

    var stopwatch = new Stopwatch();
    await dataCollector.Measure("rbk_init", stopwatch.ElapsedMilliseconds);
    ...
    await dataCollector.Measure("rbk_compiled", stopwatch.ElapsedMilliseconds);
    ...
    

    设置我的单元测试以验证我是否记录了我想要的所有统计点,我模拟了 IStatisticsCollector(IStatisticsCollector) :

    private readonly Mock<IStatisticsCollector> _statisticsCollector = new Mock<IStatisticsCollector>();
    _statisticsCollector.Setup(x => x.Measure(It.IsAny<string>(), It.IsAny<long>(), It.IsAny<IDictionary<string, string>>())).Verifiable();
    

    当我运行单元测试时,我的验证在这条线上失败:

    //assert
    _statisticsCollector.Verify(
        x => x.Measure(It.IsAny<string>(), It.IsAny<long>(), It.IsAny<IDictionary<string, string>>()), Times.Exactly(5));
    

    …显示以下消息:

    Moq.MockException : 
    Expected invocation on the mock exactly 5 times, but was 0 times: x => x.Measure(It.IsAny<string>(), (decimal)It.IsAny<long>(), It.IsAny<IDictionary<string, string>>())
    
    Configured setups: 
    IStatisticsCollector x => x.Measure(It.IsAny<string>(), (decimal)It.IsAny<long>(), It.IsAny<IDictionary<string, string>>())
    
    Performed invocations: 
    IStatisticsCollector.Measure("rbk_init", 31, null)
    IStatisticsCollector.Measure("rbk_compiled", 35, null)
    IStatisticsCollector.Measure("rbk_stored", 36, null)
    IStatisticsCollector.Measure("rbk_db_updated", 352, null)
    IStatisticsCollector.Measure("rbk_completed", 361, null)
       at Moq.Mock.VerifyCalls(Mock targetMock, InvocationShape expectation, LambdaExpression expression, Times times, String failMessage) in C:\projects\moq4\src\Moq\Mock.cs:line 378
    

    ……这很奇怪,因为看起来它捕获了5个匹配的调用,但显然没有将它们中的任何一个视为实际匹配。现在我假设这可能与秒表 ElapsedMilliseconds 是长的,但接口需要十进制(隐式强制转换),因此我更改了verify以查找 It.IsAny<decimal>() 但这给了我一个意想不到的结果:

    Moq.MockException : 
    Expected invocation on the mock exactly 5 times, but was 1 times: x => x.Measure(It.IsAny<string>(), It.IsAny<decimal>(), It.IsAny<IDictionary<string, string>>())
    
    Configured setups: 
    IStatisticsCollector x => x.Measure(It.IsAny<string>(), It.IsAny<decimal>(), It.IsAny<IDictionary<string, string>>())
    
    Performed invocations: 
    IStatisticsCollector.Measure("rbk_init", 28, null)
       at Moq.Mock.VerifyCalls(Mock targetMock, InvocationShape expectation, LambdaExpression expression, Times times, String failMessage) in C:\projects\moq4\src\Moq\Mock.cs:line 378
    

    找到了一个…只有一个。似乎没有例外,所以我不知道为什么只有一个例外。

    我还注意到可选参数上的空值,并尝试根据空值而不是 IDictionary<string, string> 但这同样没有结果。

    有人能解释这种行为吗?我需要做什么来修复我的测试?

    1 回复  |  直到 6 年前
        1
  •  3
  •   Ricardo Alves    6 年前

    此行将始终失败:

    _statisticsCollector.Verify(
        x => x.Measure(It.IsAny<string>(), It.IsAny<long>(), It.IsAny<IDictionary<string, string>>()), Times.Exactly(5));
    

    这是因为您对mock说它需要在第二个参数中接收一个long,但是接口说在第二个参数中它将接收一个decimal:

    public interface IStatisticsCollector : IDisposable
    {
        Task Measure(string metricName, decimal value, IDictionary<string, string> tags = null);
    }
    

    因为小数不能太长,所以您的验证将始终失败。