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

为什么模仿课堂这么糟糕?

  •  42
  • guerda  · 技术社区  · 15 年前

    我最近和一位同事讨论了嘲笑的问题。他说,模仿类是非常糟糕的,不应该这样做,只有在少数情况下。

    他说,只有接口应该被模拟,否则这是一个架构错误。

    我是否错过了嘲弄的意义(是的,我读过) Martin Fowler's article )

    8 回复  |  直到 15 年前
        1
  •  66
  •   Jon Skeet    15 年前

    协议 测试-它测试您将如何使用API,以及当API做出相应反应时您将如何反应。

    实际上,模拟框架在模拟类方面往往有局限性。

    根据我的经验,嘲弄有点过度使用——通常你对确切的互动并不感兴趣,你真的想要一个 树桩 ... 但是mocking框架可以用来创建存根,您会陷入通过mocking而不是存根来创建脆弱测试的陷阱。然而,要做到正确的平衡是很困难的。

        2
  •  25
  •   Pascal Thivent    15 年前

    program to an interface, not an implementation . 如果您发现自己过于频繁地模仿类,这表明您在设计体系结构时打破了以前的原则。

        3
  •  15
  •   Stefan Steinegger    15 年前

    真正的实现是在测试期间执行的 .

    当您模拟(或存根或其他)一个接口时,不存在执行您实际想要模拟的代码的风险。

    模仿类还迫使你把所有可能被模仿的东西都变成现实 事实上的 糟糕的班级设计

    如果您想解耦类,它们不应该相互了解,这就是为什么模拟(或存根或其他)其中一个类是有意义的。因此,无论如何都建议针对接口实现,但其他人在这里已经提到了这一点。

        4
  •  5
  •   Anderson Imes    15 年前

    通常,您希望模拟一个接口。

    虽然可以模拟普通类, 它会影响你的课堂设计 对于可测试性来说太多了。担心像 可访问性、方法是否是虚拟的等等都将由模拟类的能力决定 ,而不是真正的OO关注点。

    有一个名为TypeMock隔离器的伪造库,它允许您绕过这些限制(吃蛋糕,吃蛋糕),但它非常昂贵。更好地设计可测试性。

        5
  •  5
  •   Jeff Mercado    7 年前

    内置假对象 和真实的物体在一起。我在一篇博客文章中对此进行了更详细的解释: http://www.yegor256.com/2014/09/23/built-in-fake-objects.html

        6
  •  3
  •   Avdi    15 年前

    过度使用mock会导致测试无法真正测试任何东西。它还可以导致测试,这些测试是被测试代码的虚拟重新实现,紧密绑定到特定的实现。

    这都是关于节制的。

        7
  •  2
  •   Community Egal    7 年前

    他很坏,但很可笑 不是,下面的答案已经过时了。你应该参考 this answer .

    我说的是mock和stubas defined by Martin Fowler

    模拟是不好的,因为它会导致测试的过度指定。尽可能使用存根,避免模拟。

    下面是mock和stub之间的区别(来自上面的文章):

    像这样的存根。

    class OrderStateTester...
      public void testOrderSendsMailIfUnfilled() {
        Order order = new Order(TALISKER, 51);
        MailServiceStub mailer = new MailServiceStub();
        order.setMailer(mailer);
        order.fill(warehouse);
        assertEquals(1, mailer.numberSent());
      }
    

    当然,这是一个非常简单的测试- 我们还没有测试它是否被发送到 对的人,还是对的人 内容,但它可以用来说明 重点。

    使用mock这个测试看起来非常简单

    class OrderInteractionTester...
      public void testOrderSendsMailIfUnfilled() {
        Order order = new Order(TALISKER, 51);
        Mock warehouse = mock(Warehouse.class);
        Mock mailer = mock(MailService.class);
        order.setMailer((MailService) mailer.proxy());
    
        mailer.expects(once()).method("send");
        warehouse.expects(once()).method("hasInventory")
          .withAnyArguments()
          .will(returnValue(false));
    
        order.fill((Warehouse) warehouse.proxy());
      }
    }
    

        8
  •  2
  •   Moa    14 年前

    模拟类是有意义的,这样可以在开发生命周期的早期编写测试。

    即使有了具体的实现,仍然有继续使用模拟类的趋势。还有一种趋势是,当系统的某些部分尚未构建时,开发项目早期必需的模拟类(和存根)。

    一旦构建了系统的一部分,就有必要对其进行测试,并继续对其进行测试(用于回归)。在这种情况下,从mock开始是好的,但是应该放弃它们,以便尽快实现。我看到过一些项目在挣扎,因为不同的团队继续开发模仿的行为,而不是实现(一旦可用)。

    然后,您可以开发与mock一起工作的代码。当模拟不能真正代表实际的竣工系统的行为时(例如,模拟中没有看到的延迟问题、模拟中没有看到的资源和效率问题、并发性问题、性能问题等),您现在必须维护一系列毫无价值的模拟测试。

    我认为使用嘲讽在开发开始时是有价值的,但这些嘲笑不应该有助于项目覆盖。最好以后移除模拟,并创建适当的集成测试来替换它们,否则您的系统将无法在模拟未模拟(或相对于真实系统模拟错误)的各种条件下进行测试。

        9
  •  2
  •   Piotr Niewinski    4 年前

    当您模拟所有内容时,您最终会使用了解您的实现的所有内容的测试(白盒测试)。您的测试不再记录如何使用系统-它们基本上是其实现的镜像。

    根据我的经验,这是与过度嘲弄有关的最大问题之一。它会变得痛苦,需要时间,很多时间。 一些开发人员担心重构代码需要多长时间。

    模拟当然倾向于违反DRY原则,在两个地方复制代码:一个在生产代码中,一个在测试中。