【问题标题】:Can you help me understand Moq Callback?你能帮我理解起订量回调吗?
【发布时间】:2011-02-19 11:05:34
【问题描述】:

使用 Moq 并查看了Callback,但我一直无法找到一个简单的示例来了解如何使用它。

你有一个小的工作 sn-p 可以清楚地说明如何以及何时使用它?

【问题讨论】:

    标签: .net moq


    【解决方案1】:

    难以击败https://github.com/Moq/moq4/wiki/Quickstart

    如果这还不够清楚,我会称之为文档错误...

    编辑:回应您的澄清...

    对于您执行的每个模拟方法Setup,您可以指示以下内容:

    • 输入限制
    • 导出返回值(如果有)的值/方式

    .Callback 机制说“我现在无法描述它,但是当这样的呼叫发生时,给我回电话,我会做需要做的事情”。作为同一流畅调用链的一部分,您可以通过 .Returns" 控制返回的结果(如果有)。在 QS 示例中,一个示例是它们使返回的值每次都增加。

    一般来说,您不会经常需要这样的机制(xUnit 测试模式有术语用于测试中类似条件逻辑的反模式),如果有任何更简单或内置的方法来确定您需要什么,应该优先使用它。

    Part 3 of 4 in Justin Etheredge's Moq series 覆盖它,there's another example of callbacks here

    可以在Using Callbacks with Moq 帖子中找到一个简单的回调示例。

    【讨论】:

    • 嗨鲁本,我正在学习起订量,如果你愿意,我会构建大量示例来了解如何使用它来做事。我的问题是我不明白什么时候使用它。一旦我明白问题解决了,我将编写自己的代码。如果你用你自己的话来解释它,你什么时候使用回调?感谢感谢您的时间
    • 难以击败 [link]?一点也不。该链接向您展示了如何 做许多不同的事情,但没有告诉您为什么您需要做任何事情。我发现这是模拟文档中的一个常见问题。我发现的关于 TDD + mocking 的良好、清晰解释的数量可以指望为零。大多数人假设我有一定的知识水平,如果我有,我就不需要阅读这篇文章了。
    • @Kyralessa:我同意你的观点。我个人有相当多的书籍知识,所以发现快速入门的东西绝对完美。不幸的是,我不知道有一个比我在帖子末尾链接到的更好的例子。如果您找到了,请在此处发布,我很乐意对其进行编辑(或随意 DIY)
    • “我会做需要做的事情并告诉你返回的结果(如果有的话)”我认为这是误导,AFAIU Callback 与返回值无关(除非你碰巧通过代码链接它)。基本上,它只确保在每次调用之前或之后调用回调(取决于您分别在 Returns 之前还是之后链接它),简单明了。
    • @OhadSchneider 按照我的链接...你是对的!想知道(但不是很感兴趣,因为很长一段时间没有使用 Moq)Fluent 界面是否发生了变化(似乎不太可能,即我做了一个错误的假设并且没有阅读我通常会解决的链接的内容)来自我自己的自动完成)。希望修复解决您的问题,如果没有,请告诉我
    【解决方案2】:

    这是一个使用回调来测试发送到处理插入的数据服务的实体的示例。

    var mock = new Mock<IDataService>();
    DataEntity insertedEntity = null;
    
    mock.Setup(x => x.Insert(It.IsAny<DataEntity>())).Returns(1) 
               .Callback((DataEntity de) => insertedEntity = de);
    

    替代的泛型方法语法:

    mock.Setup(x => x.Insert(It.IsAny<DataEntity>())).Returns(1) 
               .Callback<DataEntity>(de => insertedEntity = de);
    

    然后你可以测试类似的东西

    Assert.AreEqual("test", insertedEntity.Description, "Wrong Description");
    

    【讨论】:

    • 对于那种特殊情况(取决于你是否试图表达对状态或行为的测试),在某些情况下使用 It.Is&lt;T&gt;Mock.Verify 而不是用临时工乱扔测试。但是 +1,因为我敢打赌,有很多人会从一个例子中得到最好的结果。
    【解决方案3】:

    Callback 只是一种在调用模拟方法之一时执行您想要的任何自定义代码的方法。这是一个简单的例子:

    public interface IFoo
    {
        int Bar(bool b);
    }
    
    var mock = new Mock<IFoo>();
    
    mock.Setup(mc => mc.Bar(It.IsAny<bool>()))
        .Callback<bool>(b => Console.WriteLine("Bar called with: " + b))
        .Returns(42);
    
    var ret = mock.Object.Bar(true);
    Console.WriteLine("Result: " + ret);
    
    // output:
    // Bar called with: True
    // Result: 42
    

    我最近遇到了一个有趣的用例。假设您期望对您的模拟进行一些调用,但它们同时发生。所以你无法知道他们被调用的顺序,但你想知道你期望的调用确实发生了(不管顺序如何)。你可以这样做:

    var cq = new ConcurrentQueue<bool>();
    mock.Setup(f => f.Bar(It.IsAny<bool>())).Callback<bool>(cq.Enqueue);
    Parallel.Invoke(() => mock.Object.Bar(true), () => mock.Object.Bar(false));
    Console.WriteLine("Invocations: " + String.Join(", ", cq));
    
    // output:
    // Invocations: True, False
    

    顺便说一句,不要被误导性的“Returns之前”和“Returns之后”的区别搞糊涂了。这只是您的自定义代码是否将在 Returns 被评估之后或之前运行的技术区别。在调用者看来,两者都会在返回值之前运行。事实上,如果方法是void-returning,你甚至不能调用Returns,但它的工作原理是一样的。如需更多信息,请参阅https://stackoverflow.com/a/28727099/67824

    【讨论】:

      【解决方案4】:

      起订量中有两种Callback。一个发生在调用返回之前;另一个发生在调用返回之后。

      var message = "";
      mock.Setup(foo => foo.Execute(arg1: "ping", arg2: "pong"))
          .Callback((x, y) =>
          {
              message = "Rally on!";
              Console.WriteLine($"args before returns {x} {y}");
          })
          .Returns(message) // Rally on!
          .Callback((x, y) =>
          {
              message = "Rally over!";
              Console.WriteLine("arg after returns {x} {y}");
          });
      

      在这两个回调中,我们可以:

      1. 检查方法参数
      2. 捕获方法参数
      3. 更改上下文状态

      【讨论】:

      【解决方案5】:

      除了这里的其他好答案之外,我还使用它在引发异常之前执行逻辑。例如,我需要存储所有传递给方法的对象以供以后验证,并且该方法(在某些测试用例中)需要引发异常。在Mock.Setup(...) 上调用.Throws(...) 会覆盖Callback() 操作并且永远不会调用它。但是,通过在回调中抛出异常,您仍然可以完成回调必须提供的所有好处,并且仍然抛出异常。

      【讨论】:

        猜你喜欢
        • 2021-06-11
        • 1970-01-01
        • 2011-04-02
        • 2012-06-05
        • 2014-10-13
        • 2020-04-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多