4

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

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

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

亲爱的SOers,您对此有何看法?

4

5 回答 5

3

我读了2个问题:

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

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

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

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

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

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

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

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

于 2009-10-22T12:09:18.400 回答
2

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

《单元测试的艺术》一书在这些领域有很多很好的建议。

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

于 2009-10-21T17:12:40.893 回答
1

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

于 2009-10-21T16:16:12.803 回答
1
  1. 在您的代码维护期间,一些初级员工会破坏运行“控制器以特定顺序调用某某方法”的代码部分的概率是多少?

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

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

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

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

如果您在一个应用程序中工作,其中一个小错误可能会产生数百万美元或更糟的后果(想想航天飞机软件,或巡航导弹的制导系统),那么全面覆盖的彻底测试变得更加有意义。

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

于 2009-10-21T17:10:42.130 回答
1

这取决于您如何对程序的域进行建模。

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

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

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

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

于 2009-10-21T17:25:50.103 回答