程序演变和破碎测试

时间:2010-01-13 03:25:55

标签: unit-testing testing

维护单元测试很困难。我确信我们都经历过一个时刻,对被测系统的看似微小的变化导致数十个单元测试失败。有时这些故障揭示了SUT中的错误,但通常测试已经过时,不再反映SUT的正确行为。在这些情况下,有必要修复损坏的测试。

你遇到过这种情况吗?经常发生吗?你介绍了什么变化以及失败是如何表现出来的?你修复了破损的测试或者只是删除了它们吗?如果是前者,怎么样?如果是后者,为什么?对失败的恐惧如何影响您编写测试的愿望?

我还想找到破损测试的具体例子。您是否知道任何以导致测试失败的方式发展的开源应用程序?

12 个答案:

答案 0 :(得分:6)

当您意外破坏代码时,是不是单元测试的全部内容告诉您?我永远不会删除失败的测试,除非它正在执行将从我的系统中删除的代码;您必须将测试创建和维护视为编写软件的一个组成部分,与交付的代码一样重要。

答案 1 :(得分:6)

  

对失败的恐惧如何影响   你想写测试的愿望?

对失败的恐惧驱使我写测试的欲望。一个测试套件让我立即反馈我的最后一次更改是否破坏了什么,以及它破坏了什么。害怕改变你的代码,不知道是否有效。

答案 2 :(得分:6)

  

难以维持单元测试。

真的。 生产代码和测试代码的共同演化很难。两种代码都有相似之处(例如命名约定),但它们的性质仍然不同。例如,必要时可以在测试代码中违反DRY;确实很容易找到代码重复,因为测试会在两个地方都破坏。测试和生产代码之间的张力有时会导致特定的设计权衡(例如依赖注入),以便于测试。同样,这些紧张局势相对较新,生产规范设计与维护工作之间的关系尚不清楚。文章“On the interplay between software testing and evolution”很棒(我无法在PDF中找到它,但很长时间没有google)。

  

我相信我们都有   经历了一个貌似的时刻   对被测系统的微小改动   导致数十个单元测试失败。   有时这些失败揭示了错误   在SUT中,但通常是测试   过时了,不再反映了   SUT的正确行为。在这些   情况下,有必要修复   破坏的测试。

缺陷本地化 - 测试套件精确定位缺陷的能力 - 也只是部分理解。设计测试套件导致高缺陷本地化的最佳策略是什么并不清楚。大多数测试在它们之间有一些重叠,这导致低缺陷定位。订购测试使他们相互依赖改善了这方面,但同时违背了孤立测试的原则。我们看到人们越来越意识到这种紧张局势,但解决这些问题并没有明确的解决方案。这是一篇关于exploiting dependencies between tests的文章。

过时或无关的测试(那些最后没有涉及任何内容的人)的问题也越来越多。测试覆盖率不够,高质量的测试套件需要经验,或者至少需要一些教育。请参阅有关the 100% coverage myth的文章。

  

对失败的恐惧如何影响   你想写测试的愿望?

您必须在(1)投入测试套件的初始时间(2)维护工作和(3)测试套件的有效性之间找到余额。我主要写的是我所谓的“拐点测试”和my view这个主题。

答案 3 :(得分:3)

  

我相信我们都经历过   一个看似微小变化的时刻   到被测系统造成了数十个   单元测试失败。

这是你的麻烦。问题不在于维护测试,问题是你有一个脆弱的代码库。如果一个更改导致数十个失败,您要么拥有一个包含大量脆弱耦合的代码库,要么是一个包含大量伪集成测试的测试套件,这些测试套件测试过多。

如果一个更改打破了几十个测试,那么您可能需要花一些时间来重构代码中重度耦合的部分,或者您需要打破测试并消除重复的测试条件。

答案 4 :(得分:2)

我观察过,并且肯定在某处,herehere读取,测试实现的单元测试更加脆弱,测试代码行为的测试。或者,白盒单元测试比黑盒单元测试更脆弱。例如,当存储实现发生变化时,对存储 thing 的类的测试将直接查看对象数据成员以验证是否存储了内容。

答案 5 :(得分:1)

就我个人而言,我认为这是不可避免的。您可以通过隔离效果来最小化效果,但有时可能会非常困难。模拟可以提供帮助,但即使它们有时也难以使用。如果行为发生了变化,并且行为改变是有意的,并且您的Y测试依赖于行为,那么您只需更改所有Y期望就有意义了。我发现通过做一些OOP,或者只是适当的套件设计,有时可以通过代码重用的优势来保存。我从不害怕在这方面的测试失败,如果行为需要改变(你已经考虑到了这种需要,需要是真实的,而且需要的不是你的经理曾经常常在好人中写COBOL的心血来潮'天:-)然后它只是进化代码库的一部分,应该被视为要完成的工作的一部分。如果测试套件的重新考虑因素需要很长时间,您可以从构建中排除测试并逐个重新包含它们,但不应删除仍然测试预期行为的测试但重新考虑因素。如果可以避免的话,不要让测试套件侵蚀以获得新功能。

答案 6 :(得分:1)

您描述的问题是在项目开始时最好解决的问题。从您开始编写单元测试(最好是TDD风格)的那一刻起,您应该始终了解展开和发展的方式。
这里没有魔术,你必须仔细思考并注意当你创造一个混乱的混乱时,实际上会使维护测试变得更加困难。通常情况下,如果测试结果如此混乱,则意味着某些生产代码也可能会使用一些重构。

基本上,重构以确保更改已本地化,并且您不必仅仅因为您决定进行简单更改而更改200个测试用例。可以说你的代码应该足够精细以便于测试(在调用代码和测试代码之前不需要存根十个对象),这通常会使它在几个月内更容易维护。

您的测试的全部目的是为您提供信心。更重要的是,它们让你变得有点愚蠢。如果你已经有足够多的测试,那么在删除几行代码之前你就不必费心思考了。删除它们并运行测试!
因为我认为这是单元测试的主要优势之一,所以我会尽我所能阻止测试套件成为我“害怕”的东西。如果简单的更改会破坏您从未期望过的地方的测试,通常意味着您需要了解更多有关您的代码库的信息,并且可能会对整理过程进行一些更改。

在极少数情况下,我删除了测试用例中未删除的测试代码。这意味着即使在深挖(回到版本控制系统)之后,我也无法理解为什么测试存在,或者不同意它。但我看待它的第一种方式是“该死的,我错过了什么”。这就是他应该如何确定他的套房,这就是为什么值得努力的原因。

答案 7 :(得分:1)

破碎的测试在实践中是一个大问题。我看到许多团体放弃了激进的测试,因为维持破坏测试的成本是压倒性的。以下是可能感兴趣的相关演讲。 https://sites.google.com/a/allegheny.edu/regression-2012/acknowledging-the-elephant-in-the-room-brittle-test-cases

答案 8 :(得分:0)

如果在对软件进行少量更改时,许多测试都会中断,那么您的测试编写得不是非常强大。编写测试以验证代码的行为而不是实现是很重要的。您还需要确保每个测试尽可能独立。

在许多情况下,使代码更容易测试所需的更改将产生提高代码质量的副作用 - 例如,通过帮助定义组件之间的接口。

答案 9 :(得分:0)

对于我几年前工作的一些软件,我对此的回答是在运行时准备一系列测试以及这些测试的正确答案。由于软件中的更改可能会将输出更改为另一个(备用)正确输出,因此我建立了一个测试输出备份系统。使用该系统,我能够跟踪测试输出中的变化并发现意外错误,并通过使用当前输出和过去输出之一之间应用的差异程序来跟踪它们何时发生。
我的测试旨在通过​​不同的配置选项遍历程序中的每个主循环。
这是在Windows-NT之前所以一切都是用DOS批处理文件和DOS实用程序完成的。
我也是编写了一个批处理文件增强器,它允许我执行类似于UNIX查找和xargs工作方式的程序。

答案 10 :(得分:0)

此问题称为单元测试脆弱性。通常情况下,测试与测试类之间的耦合过高会造成这种情况。

您应该将测试视为一段代码的客户端,其方式与其他代码是客户端的方式相同。测试应该对代码的工作方式有一定的期望,但它不应该知道细节。如果你需要了解一个类如何工作来测试它,那么你和你正在测试的代码之间可能需要另一层抽象。

随意创建仅用于测试的抽象层。测试代码与生产代码一样重要,应该像其他任何东西一样编写和设计。有时,间接层会使您的测试变得不那么脆弱,并且意味着当某些事情发生变化时,变更只会在一个地方。

答案 11 :(得分:0)

这是一个思想实验。 它只是一个咆哮

请尝试不要维护单元测试。

然后告诉一位不同学科的工程师,你已经让你的测试计划被淘汰了。 您的更改现在仅在整个事物组合在一起时进行测试。

(顺便说一下,这个测试方案有一个名字:“Big bang integration”:当你在电子产品中尝试它时,它真的是一声巨响,因为所有设备都会着火。)

解释要维护多少工作,而不是节省时间。

看着他们脸上的表情。为了达到最佳效果,请选择您所在地区的持牌PE(专业工程师)。

重复此操作,但替换ISO 9000审核员中的人员,在那里向他们展示修订后的开发程序,该程序在整合之前没有测试。

再次重复,替换CMMI评估员。最后一个会很有趣。 CMMI SCAMPI评估员喜欢像“太努力”这样的解释

现在,您可能认为自己没有使用ISO9000或CMMI工作,也从未与其他代理工程师合作。

此时,问题在于普通软件商店可能根本不进行单元测试。

所以接受平均水平,并使用既定的行业最差实践。然后离岸外包到<插入比您住的地方便宜的国家> 也不会产生任何质量影响(没有更糟糕的过程)。所以,真的,你的老板现在应该离开工作并省钱。这个推理在某处出现了问题。