【问题标题】:Moq - Ordered Setups (Expectations)起订量 - 订购设置(预期)
【发布时间】:2010-11-30 08:01:24
【问题描述】:

我对最小起订量相当陌生,无法弄清楚如何订购设置。我有以下代码:

_orderRepository.Setup(r => r.Update(It.Is<Order>(a => ((int)a.OrderStatusReference.EntityKey.EntityKeyValues[0].Value) == 2)))
                        .Throws(exception)
                        .AtMost(5);

我希望它被执行 5 次(如果更新失败,它的重试逻辑)。第 5 次后我想设置并期望它成功(不抛出异常):

_orderRepository.Setup(r => r.Update(It.Is<Order>(a => ((int)a.OrderStatusReference.EntityKey.EntityKeyValues[0].Value) == 2))).AtMostOnce();

不幸的是,它继续使用第一个代码示例,并且从未成功更新。

如果我没有使用 Throws 方法,那么我可以使用 Callback 方法,但是它在 throw 后不可用:(.

如果有办法或者这是起订量的限制吗?

【问题讨论】:

  • 您使用的是什么版本的起订量?我的版本不允许我在 Setup() 之后指定 AtMost(5) 和 AtMostOnce()...
  • 版本 3.1.0.0,奇怪的是它不允许你指定它们,你怎么会期望它只被调用 x 次!?也许旧版本使用不同的方法?
  • 好的,我对此进行了深入研究。事实证明,AtMost 和 AtMostOnce 是隐藏的,如下所述:clariusconsulting.net/blogs/kzu/archive/2009/01/08/115183.aspx 这强烈地向我表明,这种定义方法被调用次数的方式即将淘汰。我可能错了,但 Verify 方法提供了 IntelliSense 可见的替代方法。
  • “AtMost 和 AtMostOnce 被隐藏”.. 从智能感知中隐藏?它对我来说不是隐藏的!你用的是什么版本?我希望它不会消失……Verify 方法需要额外的代码行,并且会使测试变得凌乱且难以阅读。我总是可以添加一个扩展来维护 AtMostOnce...感谢您的研究。
  • 作为记录,我使用的是 3.1.something - 不记得确切的版本,但它比 3.1.0.0 高一点...

标签: .net unit-testing moq


【解决方案1】:

起订量不支持预期排序。详情请见here

虽然我目前使用的是起订量,但我以前也使用过 RhinoMocks,而且它肯定有一些我偶尔会错过起订量的功能 - 有序预期就是其中之一。

【讨论】:

  • 我在发帖之前确实阅读了那篇文章,但我希望一年后他们看到了意义并为我们提供了该功能!嗯,如果我有时间,我将不得不尝试推出我自己的“排序机制”。如果我有我的方式,下一个项目将使用 RhinoMocks! :)...谢谢。
【解决方案2】:

呸……有办法!

您可以使用 Queue 来返回返回值列表(策略在这里解释得很好:http://haacked.com/archive/2009/09/29/moq-sequences.aspx)。

这是该博客的示例:

如果你想让它工作(它不):

reader.Setup(r => r.Read()).Returns(true);
reader.Setup(r => r.Read()).Returns(true);
reader.Setup(r => r.Read()).Returns(false);

只需这样做:

Queue listOfOperations = new Queue<bool>(new bool[] { true, true, false });

reader.Setup(r => r.Read())
  .Returns(() => listOfOperations.Dequeue());

每次调用 Read() 时都会使用队列中的一个新值。

享受吧!

【讨论】:

  • 没关系,你可以使用回调来做同样的事情。这个问题是指在 Throw 方面这样做。我需要它抛出 x 次然后返回。
  • 你是对的......我错过了。对困惑感到抱歉。我将把它留在这里,因为它是一个很好的返回模式,但是这里仍然不支持 throws 情况,除非你可以从 Returns 中抛出。
  • 只是提醒一下,但最后一段代码不正确。这将始终返回 true。队列创建需要超出设置
  • 你是对的......我最近写了一个类似的关闭错误。我已经吸取了教训:)
  • .Returns(listOfOperations.Dequeue()) 应该是 .Returns(() => listOfOperations.Dequeue()) 或 .Returns(listOfOperations.Dequeue) (缺少括号)。否则,您将 .Read() 的返回值绑定到 listOfOperations.Dequeue() 在绑定时返回的值,这将导致它每次都返回 true,而与您调用它的次数无关
【解决方案3】:

我也需要同样的东西,最后写了这个对我有用的扩展方法:

public static class MoqExtensions {
    public static void Returns<TMock,TResult>(this ISetup<TMock, TResult> source, params TResult[] results) where TMock : class {
        int currentResultIndex = 0;

        source.Returns (() => {
            if(currentResultIndex >= results.Length) {
                currentResultIndex = 0;
            }

            return results [currentResultIndex++];
        });
    }
}

示例用法是:

someMock.Setup(o => o.AMethodWithReturnTypeInt()).Returns(1, 2, 3, 4);

对于这个示例,如果您调用存根方法 - 比如说 - 6 次,它将分别返回 1、2、3、4、1、2。

希望这会有所帮助...

【讨论】:

    猜你喜欢
    • 2016-11-25
    • 2012-08-26
    • 2019-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多