【问题标题】:Moq Invocation was not performed on the mock未在模拟上执行最小起订量调用
【发布时间】:2009-07-24 19:40:03
【问题描述】:

试图了解 verifySet 等的使用......但除非我采取解决方法,否则我无法让它工作。

public interface IProduct
{
    int  Id { get; set; }
    string Name { get; set; }
}


public void Can_do_something()
{
    var newProduct = new Mock<IProduct>();
    newProduct.SetupGet(p => p.Id).Returns(1);
    newProduct.SetupGet(p => p.Name).Returns("Jo");

    //This fails!! why is it because I have not invoked it
    newProduct.VerifySet(p => p.Name, Times.AtLeastOnce());

    //if I do this it works
    newProduct.Object.Name = "Jo";
    newProduct.VerifySet(p => p.Name, Times.AtLeastOnce());
 }

有人可以澄清我应该如何在属性上使用 VerifySet 和 Verify 和 VerifyGet 吗? 我越来越糊涂了。

【问题讨论】:

    标签: unit-testing mocking moq


    【解决方案1】:

    您需要在调用 verify 之前执行一项操作。带有模拟对象的典型单元测试范例是:

    // Arrange
    // Act
    // Assert
    

    因此,以下是不正确的用法,因为您缺少 Act 步骤:

    public void Can_do_something()
    {
        // Arrange
        var newProduct = new Mock<IProduct>();
        newProduct.SetupGet(p => p.Name).Returns("Jo");
    
        // Act - doesn't exist!
        // Your action against p.Name (ie method call), should occur here
    
        // Assert
        // This fails because p.Name has not had an action performed against it
        newProduct.VerifySet(p => p.Name, Times.AtLeastOnce());
    }
    

    这是正确的,因为 Act 存在:

    public void Can_do_something()
    {
        // Arrange
        var newProduct = new Mock<IProduct>();
        newProduct.SetupGet(p => p.Name).Returns("Jo");
    
        // Act
        LoadProduct(newProduct.Object);
    
        // Assert
        newProduct.VerifySet(p => p.Name, Times.AtLeastOnce());
    }
    
    public static void LoadProduct(IProduct product)
    {
        product.Name = "Jo";
    }
    

    模拟测试遵循与非模拟测试不同的模式,即 行为验证 - 这是我创建的 answer,它将更清楚地阐明这个概念。

    【讨论】:

      【解决方案2】:

      您以正确的方式使用了 VerifySet(),您只是从典型的//Act 阶段省略了

      //Arrange
      
      //Act
      
      //Assert
      

      测试构造。正如你所建议的,插入

      newProduct.Object.Name = "Jo";
      

      进入 //Act 阶段可以解决问题。

      VerifyGet() 将以完全相同的方式使用,例如

      //Arrange
      var newProduct = new Mock<IProduct>();
      newProduct.SetupGet(p => p.Id).Returns(1);
      newProduct.SetupGet(p => p.Name).Returns("Jo");
      
      //Act
      string productName = newProduct.Object.Name;
      
      //Assert
      newProduct.VerifyGet(p => p.Name, Times.AtLeastOnce());
      

      newProduct.Verify() 用于验证您指定的任何操作,例如

      //Arrange
      var newProduct = new Mock<IProduct>();
      newProduct.SetupGet(p => p.Id).Returns(1);
      newProduct.SetupGet(p => p.Name).Returns("Jo");
      
      //Act
      newProduct.Object.SomeMethodYouDefineOnTheProductObject();
      
      //Assert
      newProduct.Verify(p => p.SomeMethodYouDefineOnTheProductObject(), Times.AtLeastOnce());
      

      【讨论】:

        【解决方案3】:

        安排:

        指示模拟对象在测试期间会发生什么。告诉它会触发哪些事件,将使用哪些方法和属性,以及当这些事情发生时该怎么做。

        法案:

        执行被测代码。

        断言:

        询问模拟对象是否真的发生了你告诉他们所期望的事情。还要检查您的代码,看看它是否按预期工作。

        你的问题是你安排然后断言没有在中间采取行动。验证系列方法断言你所说的会发生在Setup方法中确实发生了。

        【讨论】:

          【解决方案4】:

          谢谢大家 不幸的是,我对这一切都很陌生,并试图快速学习。尤其是术语“行为”“安排”等

          所以即使我不明白我在做什么,我还是正确地做到了

          newProduct.Object.Name = "乔";

          正在建立一个行为。

          很棒的解释伙计们 非常感谢

          最后一件事 我认为这些会“设置并采取行动”,但事实并非如此,是吗? 你知道两个 SetupProperty 和 SetupSet/Get 之间的区别吗

          mock.SetupProperty(f => f.Surname, "foo");

          mock.SetupSet(foo => foo.Surname = "foo");

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2018-06-04
            • 1970-01-01
            • 2011-01-25
            • 2011-11-17
            • 1970-01-01
            • 2010-10-13
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多