【问题标题】:Are mock frameworks and high test coverage important?模拟框架和高测试覆盖率重要吗?
【发布时间】:2009-10-21 16:14:31
【问题描述】:

模拟框架,例如EasyMock,使插入虚拟依赖项更容易。话虽如此,使用它们来确保如何调用特定组件上的不同方法(以及以什么顺序)对我来说似乎很糟糕。它将行为暴露给测试类,这使得维护生产代码变得更加困难。而且我真的没有看到好处;在精神上,我觉得我被束缚在一个沉重的球上。

我更喜欢只针对接口进行测试,将测试数据作为输入并断言结果。更好的是,使用一些自动生成测试数据的测试工具来验证给定的属性。例如将一个元素添加到列表中,然后立即删除它会产生相同的列表。

在我们的工作场所,我们使用提供测试覆盖率的 Hudson。不幸的是,它很容易让人盲目地痴迷于一切都经过测试。我强烈认为,如果一个人也想在维护模式下保持生产力,就不应该测试所有东西。一个很好的例子是 Web 框架中的控制器。通常它们应该包含很少的逻辑,在我看来,使用控制器以特定顺序调用某某方法的模拟框架进行测试是荒谬的。

尊敬的 SOers,您对此有何看法?

【问题讨论】:

    标签: frameworks mocking easymock


    【解决方案1】:

    我读了 2 个问题:

    您对测试组件上的特定方法按特定顺序调用有何看法?

    我过去曾对此犯规。这些天我们使用更多的“存根”和更少的“嘲笑”。 我们尝试编写只测试一件事的单元测试。当我们这样做时,通常可以编写一个非常简单的测试 与大多数其他组件的交互。而且我们很少断言排序。这有助于使测试不那么脆弱。

    只测试一件事的测试更容易理解和维护。

    此外,如果您发现自己必须为与大量组件的交互编写大量期望,那么您正在测试的代码很可能存在问题。如果很难维护测试,您正在测试的代码通常可以重构。

    是否应该沉迷于测试覆盖率?

    在为给定类编写单元测试时,我非常着迷于测试覆盖率。它可以很容易地发现我没有测试过的重要行为。我还可以判断哪些部分我不需要覆盖。

    整体单元测试覆盖率统计?只要他们很高,就不是特别感兴趣。

    整个系统的 100% 单元测试覆盖率?完全不感兴趣。

    【讨论】:

      【解决方案2】:

      我同意 - 我赞成严重倾向于状态验证而不是行为验证(对 classical TDD 的松散解释,同时仍在使用测试替身)。

      The Art of Unit Testing 这本书在这些方面有很多很好的建议。

      100% 的测试覆盖率、GUI 测试、测试 getter/setter 或其他无逻辑代码等似乎不太可能提供良好的 ROI。在任何情况下,TDD 都将提供高测试覆盖率。测试什么可能会损坏。

      【讨论】:

      • 除非你的 getter/setter 突然被重写以改变逻辑并且这样做被破坏(毕竟,拥有一个 getter/setter 方法而不是一个公共成员的全部意义就是这样他们的实现可以改变)......然后你开始希望你测试你的getter/setter
      • 顺便说一句,我上面的评论是基于发生这种情况时的真实情况,我非常高兴我确实对这些进行了测试。
      • @DVK - 是的,如果 getter/setter 有逻辑,则应该对其进行测试。
      【解决方案3】:

      这取决于您如何为程序的域建模。

      如果您根据存储在数据结构中的数据和从一种数据结构中读取数据并将派生数据存储在另一种数据结构中的方法(过程或函数取决于您的设计的过程或功能)对域进行建模,则模拟对象不合适。所谓的“基于状态”的测试就是你想要的。您关心的结果是一个过程将正确的数据放入正确的变量中,而实现这一点的方法只是一个实现细节。

      如果您根据对象协作的消息传递通信协议对域进行建模,那么协议就是您关心的内容,并且对象存储哪些数据以在它们所扮演角色的协议中协调它们的行为只是实现细节。在这种情况下,模拟对象是工作的正确工具,并且基于状态的测试将测试与不重要的实现细节联系得太紧密。

      而且在大多数面向对象的程序中都有多种风格。一些代码将编写纯函数式,转换不可变的数据结构。其他代码将协调对象的行为,这些对象会随着时间的推移改变其隐藏的内部状态。

      至于高测试覆盖率,它并没有告诉你太多。低测试覆盖率会告诉您测试不足的地方,但高测试覆盖率不会告诉您代码经过充分测试。例如,测试可以通过代码路径运行,从而增加覆盖率统计数据,但实际上并没有对这些代码路径的作用做出任何断言。此外,真正重要的是程序的不同部分如何组合起来,单元测试覆盖率不会告诉你。如果您想验证您的测试是否真的在充分测试您的系统行为,您可以使用 Mutation Testing 工具。这是一个缓慢的过程,因此您需要在夜间构建中运行,而不是在每次签入时运行。

      【讨论】:

        【解决方案4】:

        我曾问过一个类似的问题How Much Unit Testing is a Good Thing,这可能有助于了解人们认为合适的各种测试级别。

        【讨论】:

          【解决方案5】:
          1. 在您的代码维护期间,一些初级员工会破坏运行“控制器以特定顺序调用某某方法”的代码部分的概率是多少?

          2. 如果发生这种情况,贵组织的成本是多少?生产中断、调试/修复/重新测试/重新发布、法律/财务风险、声誉风险等...?

          现在,将 #1 和 #2 相乘,并检查您不愿意达到合理的测试覆盖率是否值得冒险。

          有时,它不会(这就是为什么在测试中有一个收益递减点的概念)。

          例如如果您维护的 Web 应用程序不是生产关键,并且有 100 个用户在应用程序损坏时有解决方法(和/或可以轻松且立即回滚),那么花费 3 个月对该应用程序进行全面测试可能是非- 感性的。

          如果您开发的应用程序中的小错误可能会造成数百万美元甚至更糟的后果(想想航天飞机软件或巡航导弹的制导系统),那么全面覆盖的彻底测试就会变得更加有意义.

          另外,我不确定我是否对您的问题阅读过多,但您似乎暗示启用模拟单元测试以某种方式排除了应用程序/集成功能测试。如果是这样,你反对这样的想法是正确的——这两种测试方法必须共存。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-01-07
            • 2020-12-22
            • 1970-01-01
            • 2012-03-25
            • 2018-10-18
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多