代码之家  ›  专栏  ›  技术社区  ›  koen

如何避免从模拟对象列表返回模拟

  •  14
  • koen  · 技术社区  · 14 年前

    我在尝试模拟/责任驱动的设计。对于需要服务来检索其他对象的对象,我似乎无法避免从mock返回mock。

    一个例子可以是检查上个月的账单是否支付的对象。它需要一个检索账单列表的服务。所以我需要在测试中嘲笑billRetrievalService。同时,我需要billRetrievalMock来返回模拟的账单(因为我不希望我的测试依赖于账单实现的正确性)。

    我的设计有缺陷吗?有更好的方法测试这个吗?或者这是使用finder对象时所需要的方式(在本例中是查找票据)?

    附带说明:虽然bill可能是一个值对象候选对象,但当集合不包含值对象(例如用户)时,更广泛的问题仍然存在。

    4 回复  |  直到 5 年前
        1
  •  13
  •   J. B. Rainsberger    5 年前

    大多数情况下,如果我需要一个mock来返回另一个mock,我会找到一个在另一个方向上更有意义的依赖项。换句话说,mock返回mock通常指向违反依赖性反转原则的行为。

    一个常见的异常是:创建对象的工厂(而不是每次只返回相同对象的“holder”)。如果我在有生之年需要创建多个相同类型的对象,那么我可能需要依赖于 ObjectFactory 调用 #createObject() ,然后可能设定对象的期望值。即便如此,我还是会质疑。调用堆栈上一级的其他内容可能会创建 Object 是给我的,必要时给我。

    ObjectHolder 案例,而不是依赖于 小精灵 得到 对象 ,我更喜欢依赖 对象 直接和强迫我的来电者给我它想要的。这尊重了 语境独立性 .

    这个问题的一个具体版本是“虚拟时钟”模式。有时你需要依赖虚拟时钟,但通常最好是简单地要求一个时间戳(“瞬时请求”模式),或者,最坏的情况下,要求一个时间戳流,无论它来自何处。测试可以提供方便的、硬编码的时间戳的受控流,但也很容易将系统时钟转换为时间戳流。

        2
  •  11
  •   Esko Luontola    14 年前

    mock返回mock是一种很强的代码味道,这可能是设计中的一个问题。可能是账单应该是不可变的值对象,而不应该被模拟。或者对类的设计和职责有一些混淆。

    Growing Object-Oriented Software, Guided by Tests Mock Roles, not Objects 从模拟对象的发明者那里值得一读。

        3
  •  5
  •   Jakub Holý    14 年前

    作为 Way of the Testuvius 建议,没有原则,无论多么好,应该采取绝对的,所以这也是与规则,你不应该需要模拟返回模拟,有些情况下,这是非常合适的。

    正如gutzofter建议的那样,您可以将对象分成两部分,一部分用于实际验证,另一部分用于检索要验证的票据。这个“单一责任”原则应用程序的优点是验证器将更通用和可重用。另一方面,如果您只有这个简单的用例,并且对更高的可重用性没有特殊需求,那么将检索和验证保持在一个类中是非常实用的。仅仅为了满足一个抽象的原则而做的,由于一个真正的需要和一个真正的利益而不合理的分层、对象数量的爆炸等,是不好的。你总是要权衡正反两面,现实很少是简单的,正如我们所希望的那样美丽:-这种实用方法的伟大例子是在Adam Bien真实世界的JavaEE模式中——重新思考最佳实践。

        4
  •  4
  •   Gutzofter    14 年前

    通常当我模仿的时候,我会得到一个三位一体的物体。第一个对象是协调器 BillsPaidLastMonthCoordinator 此对象有两个依赖项 BillRetrievalService BillPaidValidator .

    您将模拟这两个依赖项,您的测试将用于检索和将帐单传递给验证的交互。所以对于这个测试,你不会在意数据是什么。这有助于分离责任。您的原始对象负责检索 Bills 然后看看这是不是一个ispaid法案。

    用你描述问题的方式,你可能会结束一个嘈杂而脆弱的测试。脆性来自于它可以被两种方式打破。

    有了Corrdinator,如果 Bill 实现更改,只是实际使用 比尔 . 我的2世纪。

    [编辑]

    这与使用事件处理程序(协调器)更为一致