【问题标题】:How to keep Mock object in sync with target object如何使 Mock 对象与目标对象保持同步
【发布时间】:2011-07-10 01:11:10
【问题描述】:

我问的是模拟对象管理,不管具体实现(EasyMock、模拟对象等)。

我一直不愿意在我的单元测试中使用 Mock 对象,原因如下: 模拟对象的行为必须反映被模拟对象的行为。如果被模拟对象的行为发生了变化,我们也必须改变模拟对象的行为。如果不这样做,mock 对象的行为就会与真实对象不同步,从而使单元测试变得毫无意义,而且很危险。

我的问题是, 如何使模拟对象与目标对象保持同步? 你如何传播这些变化? 您是否使用任何模拟对象管理技术?

编辑: 更改标题以缩小范围。

【问题讨论】:

    标签: unit-testing version-control junit mocking


    【解决方案1】:

    定义良好的 API 不应该有这种余地:给定一组输入,被模拟的对象应该只以这些特定的方式表现:行为与接口相关联。如果允许差异,那么您的模拟对象应该测试该对象可以执行的所有不同操作。

    您可以通过以下方式降低行为漂移的风险:

    • 集成测试,以及
    • 将模拟数据与实际实现进行比较。

    【讨论】:

      【解决方案2】:

      我不是专家,但我的想法是模拟对象是为单个测试用例/交互而设计的。如果这种交互发生变化,您显然希望在测试中反映出来。但这不应该破坏一个类的所有模拟对象,因为它们会检查可能仍然有效的不同交互。

      【讨论】:

        【解决方案3】:

        如果 ClassA 调用:

         AThing aThing = ClassB.GiveMeAThing()
        

        ClassA 永远不应该关心 ClassB 是如何得到那个东西的。因此,存根(StubB)永远不应该关心存根的实际实现如何表现。只有当交互本身发生变化时——返回类型或调用参数——才应该改变 StubB,如果你想让你的代码编译就需要这样做:-)

        如果你的 ClassB 开始返回 Nulls 或 Throws 新类型的异常;好吧,那么就需要编写全新的测试,并且可能还有新的存根。

        问候, 莫腾

        【讨论】:

          【解决方案4】:

          你在正确的轨道上。您不希望每次重构被测系统时都必须更改脆弱的测试。

          总的来说,我将测试集中在公共接口上。如果您的公共接口发生更改,您可能需要更改的不仅仅是测试。

          我还尽可能地尝试进行状态测试而不是行为测试。所以我通常会使用stubs instead of mocks。 (大多数隔离/模拟框架都允许您创建。)我验证被测系统(或类)的状态,而不是要求模拟对象验证自身。

          也就是说,我尽量保持灵活。如果在给定的情况下测试模拟行为是有意义的,我会使用它。如果我需要公开内部信息以获得体面的报道,我会的。

          编辑:另见article by Scott Bain

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-03-05
            • 2015-08-29
            • 1970-01-01
            • 1970-01-01
            • 2023-03-07
            • 2013-03-29
            相关资源
            最近更新 更多