【问题标题】:Moq: How to clear expectations on a mock object?Moq:如何清除对模拟对象的期望?
【发布时间】:2011-03-08 19:00:28
【问题描述】:

一个例子 - 我想测试狙击手是否只通知视图添加的项目。

[Test]
    public void NotifiesViewOfLoss_IfCloseEventReceivedForSnipedItems()
    {
        _sniper.AddItem(TestConstants.ItemNo54321);
        _sniper.AddItem(TestConstants.ItemNo65432);

        _sniper.AuctionClosedFor(TestConstants.ItemNo65432);
        _mockView.Verify(view => view.UpdateStatus(TestConstants.ItemNo65432, AuctionSniperStatus.Lost));

        _sniper.AuctionClosedFor(TestConstants.ItemNo54321);
        _mockView.Verify(view => view.UpdateStatus(TestConstants.ItemNo54321, AuctionSniperStatus.Lost));

        _sniper.AuctionClosedFor(7);

        // doesn't work
        //_mockView.Verify(view => view.UpdateStatus(It.IsAny<int>(), It.IsAny<AuctionSniperStatus>()),
        //                Times.Never() );
    }

Times.Never 行不起作用 - 因为它与之前的调用之一匹配。 我知道还有其他选择:

  • 设置一个新的期望抛出,如果被调用(如上所示)
  • 比如指定 7 而不是 IsAny()
  • 将测试分成 2 个测试

【问题讨论】:

    标签: unit-testing moq


    【解决方案1】:

    在这种情况下,更新视图的状态不会给你任何你可以断言的“结果”,我也会选择严格的模拟。通过这种方式,您准确地设置了您希望在模拟对象上进行的调用(以及这些调用的确切数量)。当您更改模拟的类型时,您的测试将立即变得正确。

    这种方式比你的前两个选项好很多(因为即使你没有猜到正确的参数值或者忘记设置会抛出异常的期望,它也会失败测试),它也更具可读性(至少恕我直言)。

    关于拆分测试,始终建议将单元测试保持尽可能小。所以问题是你想测试当你在两次正确的呼叫之后发生这个错误的呼叫时会发生什么?还是只打一个错误的电话就足够了?

    【讨论】:

      【解决方案2】:

      如果您想断言调用您指定的方法,您可能需要考虑在此测试中对_mockView 使用严格的模拟。

      【讨论】:

      • 我想指定不为第三次 AuctionClosedFor 调用调用 UpdateStatus 方法 - 即我想在第三次调用之前清除在模拟上设置的任何 UpdateStatus 期望并断言该方法未被调用(对于尚未添加到狙击手的项目)
      【解决方案3】:

      这是一篇旧帖子,但为了完整起见,Moq 现在可以重置验证计数器 (https://stackoverflow.com/a/23549214/179311):

      _sniper.AuctionClosedFor(TestConstants.ItemNo54321);
      _mockView.Verify(view => view.UpdateStatus(TestConstants.ItemNo54321, AuctionSniperStatus.Lost));
      
      _mockView.ResetCalls();
      
      _sniper.AuctionClosedFor(7);
      _mockView.Verify(view => view.UpdateStatus(It.IsAny<int>(), It.IsAny<AuctionSniperStatus>()),
                       Times.Never() );
      

      【讨论】:

      • 此 ResetCalls() 方法现在已从 Moq 中过时。您需要替换 _mockView.ResetCalls();使用 _mockView.Invocations.Clear();继续前进。
      猜你喜欢
      • 1970-01-01
      • 2010-12-10
      • 2014-11-14
      • 1970-01-01
      • 2016-04-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多