如何处理大量失败的测试?[关闭]


22

我正在开发一个用Java编写的旧项目。我们有超过1000万个LOC,更糟糕的是,有4000多个功能测试。

由哈德森(Hudson)安排的测试由于每次较大的代码更改而疯狂,但都失败了。验证测试失败-如果是产品或测试中的问题,则需要几个月的时间。我们无法删除旧测试,因为我们不知道它们在测试什么!

我们能做什么?如何进行如此大量的传统测试?


6
真正的问题有答案。与其解释为什么您的情况糟透了,或者为什么您的老板/同事让您感到不高兴,不如说您想做些什么来使事情变得更好。有关更多信息,请单击此处 ...
gnat 2015年

13
为什么首先让测试开始失败?BTW 4000是没有那么多的测试,10 MLOC
BЈовић

6
停止,下降和滚动。
纳文

13
找出正在测试的测试。然后重新审视并想知道首先在地面上进行测试需要花费数月的时间才能发现问题,并且还发现您的需求有何变化。测试旨在封装应用程序中的需求。如果测试失败,则说明您的代码未按照要求执行-您编写的代码有误或没有代码符合要求。
Dan Pantry 2015年

6
我们都已经看到编译器由于缺少一个'}'而引发了无数错误。如果这些是具有过多依赖项的功能测试,也许是同样的问题在起作用?
丹·皮切尔曼

Answers:


37

丢下他们

我知道很难放弃显然需要付出很多努力的东西,但是测试对您没有用,它们正在对您不利。测试套件应该可以使您确信系统可以完成预期的工作。如果不这样做,那就是负债而不是资产。系统或测试是否有故障都没有关系-只要运行测试套件会发出大量错误,它就无法实现其目的。

你现在需要的是测试新套件与运行没有错误。这意味着它最初将几乎没有覆盖,实际上几乎没有覆盖。每次修复或花时间彻底了解系统知识时,您都会在测试中获得该知识。随着时间的流逝,这将产生一个新的安全网,您可以在将来建立它。试图修补一个旧的,难以理解的安全网是一个时间浪费,几乎是不值得的。

我什至提倡不要将测试从旧套件转移到新套件。当然,其中一些可能现在会成功,但这是因为他们正在准确地测试他们应该测试的东西,还是仅仅因为某些随机镜头总是能够击中目标?显然,您必须对可用的努力可以做什么和不能做什么进行务实,但是您不能妥协一个原则,即测试套件必须干净地运行才能完成其工作


9
我看不出您的逻辑:“测试套件应该让您确信系统可以完成应做的工作。错误。” 如果您有使测试失败的错误代码,并不意味着您应该重新编写测试以使错误代码通过。
DBedrenko 2015年

13
Hector的情况是他不知道代码或测试是否错误。如果这样做,他可以使用代码库并有时更改测试,有时更改业务代码。实际上,即使这样的繁琐工作也无济于事,因为您不知道自己是要解决问题还是解决问题。
Kilian Foth 2015年

5
“测试套件应该使您确信系统可以完成[应该]的工作。” 不,应该告诉我系统是否做应有的工作;错误的信心总比没有好。“您需要的是一个无错误运行的测试套件”不,他需要的是一个为他提供有关代码健全性的有用信息的测试套件。他现在拥有的是许多神秘的警示灯,这比没有进行任何测试的闪亮的新测试套件的绿灯要好。他应该暂时禁用旧测试,但不要放弃任何未经验证为伪造的测试。
Beta

4
这个答案是非常糟糕的建议!如果较小的代码更改导致大量失败的测试,则可能是代码质量问题。测试至少会通知您您损坏了某些东西。您需要改进代码(通过在测试的帮助下仔细重构)。如果仅删除测试,则无法知道是否破坏了某些内容。
JacquesB 2015年

4
这是可怕的建议。如果OP及其团队已经不了解代码库及其测试,那么扔掉测试并重新开始不太可能解决OP的核心问题-了解代码库。我认为我们可以假定测试在编写时就可以工作-因此,他的团队需要跟踪每个测试在测试什么,并阅读源代码以确定是今天的代码库还是测试错误。比从错误的,无知的/天真的测试重新开始要简单得多。
SnakeDoc

29

去修复测试。

您最大的错误是您允许测试失败,并且您显然忽略了一段时间。您拥有的不是“旧式测试”-您正在处理旧版代码。而且我认为编写的每个没有测试的代码都是遗留的。


验证测试失败-如果产品或测试存在问题,则需要花费数月的时间。我们无法删除旧测试,因为我们不知道它们在测试什么!

看起来您的组织中存在更大的问题,因为您没有明确的要求。我无法理解您(或其他人)无法确认正确的行为。


4
理想情况下应该这样做,但是似乎这里的测试太糟糕了,程序员甚至都不知道他们在测试什么。我认为在这种情况下,最好摆脱WTF测试并立即开始编写新的有意义的测试!在一个最近的项目中,我与一个同事有一个类似的问题,他的测试总是由于没有充分的理由而失败(它之所以失败是因为应该测试的东西出错了,而是因为测试代码是如此的脆弱,甚至没有确定性!) 。我花了几天的时间重写自己能做的,剩下的都浪费了!
Shautieh

@Shautieh WTF测试并非没有WTF代码,因此修复测试通常意味着重构代码。随机失败的测试是无能的标志。您同事的上司应该为自己没有做的工作负责。
2015年

2
有时生活很艰难:负责WTF测试(和代码)的人获得了团队中最高的薪水(比我高20%以上),并且在项目中期辞职时(因为他找到了更高薪水的工作) )我不得不接受他的一些开发人员:/但是您绝对可以说我们的主管也应该受到指责^^
Shautieh

@Shautieh:我的一位同事曾经说过,代码中的错误是两个错误:代码中的错误和测试中的盲点。我猜想,如果算上允许失败测试的开发人员,那实际上是3个;如果算上提倡这种无能的经理,则实际上是4个。
Beta

@Beta听起来与TDD中有时使用的定义非常相似:“错误是您尚未编写的测试。”
恢复莫妮卡2015年

22

测试很有价值。至少,他们记录到有人认为他们应该花时间来编写它们,因此大概他们一次对某人有价值。幸运的是,它们将包含团队曾经研究过的所有功能和错误的完整记录,尽管它们也可能只是一种无需仔细考虑即可达到任意测试覆盖率的方法。除非您查看它们,否则您将不知道这是什么情况。

如果您的大多数测试大部分时间都通过了,那么就硬着头皮投入时间,弄清楚几个失败的测试正在尝试做的事情,并进行修复或改进,以便下次的工作会更容易。在这种情况下,请跳至“ 确定每个测试的意图”部分,以获取有关处理少量失败测试的一些建议。

另一方面,您现在可能会面临Red版本,数百个甚至数千个测试都没有通过一段时间,而Jenkins很久没有成为绿色了。此时,Jenkins的构建状态已变得无用,并且签入问题的关键指标不再起作用。您需要解决此问题,但是在整理客厅中的混乱情况时,您无力阻止所有前进的进度。

为了保持理智,同时执行必要的考古以确定可以从失败的测试中恢复什么价值,我建议执行以下步骤:

暂时禁用失败的测试。

您可以通过多种方式来执行此操作,具体取决于您的环境,但您并未明确描述,因此我无法真正推荐任何特定的方式。

一些框架支持预期失败的概念。如果您这样做了,那就太好了,因为您将看到该类别中还剩下多少测试的倒计时,甚至还可以通知您其中一些测试是否意外通过。

一些框架支持测试组,并允许您告诉Hudson仅运行某些测试,或跳过一组测试。这意味着您偶尔可以手动运行测试组,以查看是否正在通过测试。

一些框架允许您注释或以其他方式标记要忽略的单个测试。在这种情况下,将它们作为一个团队来运行比较困难,但是这会阻止它们分散您的注意力。

您可能会将测试移至构建中通常不包含的源树。

在极端情况下,您可以从版本控制系统的HEAD删除代码,但这将使第三阶段完成时更难识别。

目标是让詹金斯(Jenkins)尽快进入绿色,以便您可以尽快朝正确的方向发展。

保持测试相关。

解决添加或修改代码时添加新测试的问题,并致力于使所有通过测试通过。

测试可能会由于各种原因而失败,包括它们并非一开始就编写得当的测试。但是,一旦让詹金斯(Jenkins)变得绿色,保持这种方式确实非常重要。

习惯于编写好的测试,如果测试开始失败,则要花很多时间。

确定每个测试的意图。

一次通过禁用测试。从影响您最经常更改的模块的模块开始。确定测试的目的以及失败的原因。

  • 它是否测试了故意从代码库中删除的功能?然后,您可以删除它。

  • 是否正在捕获尚未有人注意到的错误?恢复测试并修复错误。

  • 是否由于做出不必要的假设而失败(例如,假设按钮文本始终为英语,但是现在您已将应用程序本地化为多种语言)?然后找出如何使测试专注于单个事物,并将其与无关的更改尽可能地隔离开。

  • 测试是否扩展到整个应用程序并代表系统测试?然后将其从您的主要Jenkins测试套件中删除,并将其添加到运行频率较低的回归套件中。

  • 该应用程序的体系结构是否已发生了不可识别的变化,因此测试不再有用吗?删除它。

  • 是否添加了测试以人为地增加代码覆盖率统计信息,但实际上无非是确认代码正确编译且不会进入无限循环?否则,测试仅确认您选择的模拟框架返回了您刚刚告诉它的结果?删除它。

结果,一些测试将继续进行,一些测试将被修改,一些将被分成多个独立的,小块大小的块,而另一些将被删除。只要您仍然在新要求方面取得进展,就留出一点时间来处理技术债务,这是负责任的事情。


1
仅仅因为测试失败而禁用测试是一个非常非常糟糕的主意!您的其余建议都很好,但不是这样。您不了解的测试永远都不应被禁用。测试的重点不是获取绿色的标杆,而是获取可运行的软件!
JacquesB 2015年

这取决于问题的规模。但是我同意,实际上我还没有明确说明。
比尔·米歇尔

添加了一个段落来区分“我们是绿色的,但是每一个改变都会使东西变成红色”和“我们已经很久了,我们已经忘记了绿色的样子”
比尔·米歇尔2015年

除了禁用甚至删除测试之外,某些框架还提供了预期失败的概念。这可能有助于提高SNR,因为您将收到有关故障的更直接警报(如果总是有大量故障,则不会发生),但仍会收到有关已知故障的通知,并且-甚至更重要的是-先前未通过的测试突然又通过了。如果读取了意外故障,而预期故障为橙色,则使红色测试成为您的第一个绿色,使橙色测试成为您的第二优先。
5gon12eder 2015年

11

4000次测试是一个棘手的问题。40次测试更容易处理。随机选择可管理数量的测试以运行和分析。将结果分类为:

  1. 无用的测试
  2. 干净运行的有用测试
  3. 有用的测试失败

如果很多测试属于第一类,那么可能是时候丢弃当前的测试套件,并为当前代码组合一个有用的套件了。

如果许多测试都以告诉您代码中的问题的方式失败,则您需要通过失败的测试来解决问题。您可能会发现修复一个或两个错误会使大量测试运行。


2
+(INT)(PI / 3),用于提供的实际&简单的方式测试该测试套件-但没有-虽然我同意作为一个经验法则,如由OP描述的是一个错误的设计的标志测试,例如测试怎么了,关于测试套件本身的任何建议(例如“放弃测试”,“修复测试”,“编写新测试”)都是毫无用处的。就像您说的那样:如果我要进行4k测试,而对于40个测试中的40个,则完全随机的则是cr脚且无用的-我会毫不犹豫地放弃整个套件。如果其中的3/4实际上是有用的-我会离开并集中精力改进代码。
vaxquis

7

如果这句话是真的,

随着更大的代码更改,测试……像疯了一样失败了。

这意味着如果在“更大的代码更改”之前回滚到代码,则许多测试将再次通过。之后,获取一小部分更改,然后查看哪些测试最近失败。这将帮助您更好地隔离哪些代码更改导致哪些测试失败。对于每个测试,一旦找出问题所在,就应该能够确定新代码是否存在缺陷,或者测试是否存在缺陷。如果新代码有问题,请确保将其与最新版本进行比较,以防特定错误已得到修复。

重复直到获得最新的代码库。

这似乎是一项艰巨的任务,但是很可能一旦您走上这条道路并开始隔离某些问题,就会出现一种模式,这可能会大大加快这一过程。例如:

  • 您可能会注意到许多测试都依赖于其他有缺陷的东西。修复一个问题可能会修复许多测试。
  • 您可能会注意到许多测试存在缺陷,需要修复或删除。
  • 您可能会注意到,特定的开发人员导致测试失败的频率更高。该开发人员可能需要更多的培训或监督。

3

如果您不知道他们正在测试什么,请删除它们,直到您知道为止。测试是不稳定的事情,如果您删除不再需要的功能,则应该期望必须更改测试该功能的测试!因此,除非您知道测试在测试什么,否则您就没有希望在适当的位置更改代码库。

您可以在开发人员的计算机上设置测试系统并在其中运行,以便开发人员可以查看与测试交互的部分,希望提供缺少的文档,并更加熟悉可能未正确更改或没有更改的代码库不再正确测试。

简而言之-如果您的旧测试在更改时失败,那么您的代码更改就不好了。使用这些测试作为系统工作方式的教育手段。


1
这就是为什么我喜欢JUnit的@Ignore注释的原因-您可以保留测试,但不能执行它们。然后,只需重新启用它们并一次修复它们即可。它使您可以将重点一次缩小到仅进行少量测试,而不会因成千上万次失败而感到不知所措。
TMN

1
这是个坏建议。您不应该删除或禁用您不了解的测试。只有当你明白的考验,你有信心它测试一个已经废弃的特性,它应该被禁用或删除。
JacquesB 2015年

2

我要做的最重要的事情是回到测试应该做的基础以及业务需要保持前进的基础。测试的工作是在问题变得昂贵以后加以修复之前确定问题。我认为那句话的关键词是“昂贵”。这些问题需要业务解决方案。现场是否出现昂贵的问题?如果是这样,则测试将彻底失败。

您的管理层和您需要进行现实检查。您会发现,由于进行了一系列的测试,开发成本正在飞涨。这些成本与由于禁用测试而交付有缺陷产品的成本相比如何?与实际找出用户需要哪些行为(应测试的事物)的繁重任务相比,它们又如何呢?

这些都是需要业务解决方案的问题,因为它们涉及到工作的业务方面。您正在向客户交付产品,这是企业非常感兴趣的边界。他们可能能够确定您作为开发人员无法解决的解决方案。例如,为他们提供两种产品可能是合理的:一种针对那些需要可靠性并愿意放弃新功能的人的“传统”产品,而一种“远见”的产品可能有更多的缺点,但仍处于领先地位。这将使您有机会开发两组独立的测试:一组旧的具有4000项测试,另一组包含您认为需要完成的更多测试(并记录它们,因此该过程不再重复)。

然后,艺术就开始了:如何管理这种两头野兽,以便一个分支的发展也可以帮助另一个分支?尽管有严格的测试要求,但对“普通”分支的更新又如何又流回“旧”分支。如果您最终合并了产品,那么在“旧版”分支上继续出现的客户请求又如何能更好地帮助您理解旧客户的需求?


-3

我们无法删除旧测试,因为我们不知道它们在测试什么!

这就是为什么您应该删除旧的测试!如果您不知道他们在做什么,那么失败就毫无意义,而运行它们就是浪费时间。把它们扔出去,然后重新开始。


2
这似乎已经取得仅仅是重复点,并解释最多的回答
蚊蚋

4
失败并不是“无意义的”,它意味着您对系统的理解不尽如人意。
Ben Voigt 2015年

失败在这里绝对没有意义,因为OP明确表示他们不了解系统。
马海毛
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.