【问题标题】:Moq Verify not matching on invocationMoq 验证调用时不匹配
【发布时间】:2020-11-16 19:37:36
【问题描述】:

在开始之前,我多年来一直使用 Moq 在单元测试中模拟事物。这应该是一个简单的模拟验证,但无论出于何种原因,当它发生时,最小起订量与模拟上的调用不匹配。我已经手动测试过,它被击中了。我已经调试了测试并比较了实际值和预期值(它们匹配),我已经搜索了 SO 及其众多做公然错误的事情的人,我无法弄清楚为什么这不起作用。帮助表示赞赏。

单元测试是一个非常简单的测试,检查BulkInsert 是否在void 返回函数的末尾被调用。示例代码:

代码:

public interface IDependencyService
{
    void BulkInsert(IList<T> items);
}

public class MyServiceClass
{
    private readonly IDependencyService _service;

    /* ctor and all that jazz */

    public void Run()
    {
        /* do things to the data */
        
        _service.BulkInsert(items); // where items is an IList<T>
    }
}

测试:

public class ServiceTests
{
    [Fact]
    public void ServiceRun_Calls_DependencyBulkInsert()
    {
        var dependencyMock = new Mock<IDependencyService>();
        List<T> expected = /* somehow build expected values */
        dependencyMock
            .Setup(mock => mock.BulkInsert(It.IsAny<IList<T>>()));
        var sut = new MyServiceClass(dependencyMock.Object);
        sut.Run();

        dependencyMock.Verify(mock => mock.BulkInsert(expected), Times.Once());
    }
}

错误信息:

Expected invocation on the mock once, but was 0 times: mock => mock.BulkInsert([ThresholdCheck])
Performed invocations:

   Mock<IThresholdCheckHandler:1> (mock):

      IThresholdCheckHandler.GetQueuedChecks()
      IThresholdCheckHandler.BulkInsert([ThresholdCheck])

如果我在验证调用中将 expected 更改为 It.IsAny&lt;T&gt;(),则测试通过。这使我相信,从预期传递的对象可能以某种方式与运行程序时生成的对象有所不同。但是,如前所述,我已经使用调试器并手动将实际列表中的每个值与测试中的预期值列表进行比较,它们完全相同相同。

这让我相信我只是一只在键盘上点击的愚蠢的双足猴子,问题就在我面前,而我只是没有看到它。任何帮助或眼睛都表示赞赏。

【问题讨论】:

  • 除非预期的是传递给模拟成员的实际列表(参考),否则您描述的行为是设计使然。
  • 好吧,List 只等于它自己,即使你的两个列表具有相同的元素,它们的“等于”也会返回 false。保留使用 Callback 传递给模拟方法的列表,然后将其与预期进行比较。通过 CollectionAssert.IsEqual
  • 啊,好吧,我不认为 Verify 操作了引用,这很烦人。我真的不明白他们为什么要对引用而不是对象的相等性进行操作。感谢您的提醒,我会调查回调

标签: unit-testing .net-core moq


【解决方案1】:

根据 NKosi 的评论,Verify 通过。使用引用类型时的引用。我很困惑,因为我过去曾将 Verify 用于整数和字符串等简单的事情,但没有意识到这个怪癖。人们会假设使用验证它会检查实际与预期的等效性,但不是。

不管怎样,根据 Quercus 的评论,我将我的测试调整为这样,以便继续我的一天:

public class ServiceTests
{
    [Fact]
    public void ServiceRun_Calls_DependencyBulkInsert()
    {
        var dependencyMock = new Mock<IDependencyService>();
        List<T> actual = new List<T>();
        List<T> expected = /* somehow build expected values */
        dependencyMock
            .Setup(mock => mock.BulkInsert(It.IsAny<IList<T>>()))
            .Callback<List<T>>(l => actual = l);
        var sut = new MyServiceClass(dependencyMock.Object);
        
        sut.Run();

        actual.Should().BeEquivalentTo(expected);
    }
}

这个解决方案对我有用。感谢你们帮助我认识到我的错误。

【讨论】:

  • 由于您使用流畅的断言,您也可以在原始示例中使用It.Is&lt;IList&lt;T&gt;&gt;(actual =&gt; actual.Should().BeEquivalentTo(expected))
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-02-28
  • 2012-02-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多