在生产中发现错误时,我是否应该有意中断构建?


410

在我看来,如果最终用户在生产中发现了严重的错误,应该添加一个失败的单元测试来覆盖该错误,从而有意破坏该构建,直到修复该错误为止。我这样做的理由是构建应该一直失败,但这并不是由于自动测试覆盖率不足所致。

我的几个同事不同意说不应该检查失败的单元测试。就正常的TDD惯例而言,我同意这种观点,但是我认为应该以不同的方式处理生产错误-毕竟,为什么要允许建立已知缺陷的成功方案?

是否有其他人具有处理这种情况的可靠策略?我知道故意破坏构建可能会对其他团队成员造成破坏,但这完全取决于您使用分支机构的方式。


75
+1; 一个非常挑衅的问题。我可以看到双方。
Carl Manaster

28
您使用术语“构建”来包括“测试”,这不是一个普遍的理解。
杰伊·巴祖兹

19
如果您正在执行TDD,则将编写失败的测试,然后修复代码,然后检入。因此,您可以避免损坏的构造。
Dietbuddha 2012年

7
按照相同的逻辑,应该关闭客户端的活动实例,直到解决问题为止。不,您不应该中断构建。让处理错误的开发人员添加单元测试,并使代码一起更改。无需关闭整个过程。
Thanos Papathanasiou 2012年

Answers:


412

我们的策略是:

签入失败的测试,但用进行注释@Ignore("fails because of Bug #1234")

这样,就可以进行测试,但是构建不会中断。

当然,您会在错误数据库中注意到被忽略的测试,因此,在修复@Ignore测试后将其删除。这也可以作为错误修复的简便检查。

在失败的测试中破坏构建的意义并不是要以某种方式使团队承受压力,而是要提醒他们出现问题。一旦发现问题并将其提交到Bug DB中,就没有必要为每个构建都运行测试了-您知道它将失败。

当然,该错误仍应修复。但是安排修复时间是业务决策,因此并不是开发人员真正关心的问题……对我而言,一旦将错误提交到错误数据库中,就不再是我的问题,直到客户/产品所有者告诉我他们希望对其进行修复。


150
+1我认为您以“安排修补程序是一项商业决策”来打动您的头-作为开发人员,决定错误是否破坏构建不是我的判断力。
MattDavey 2012年

22
我认为这是一个非常明智的解决方案。特别是如果下一个要检查一些次要代码的人突然收到“测试失败”的通知,并认为这是他所做的。
Holger 2012年

14
“对我来说,一旦将错误提交到错误数据库中,就不再是我的问题了……” +1
杰克·伯杰

20
@anon在丰田公司工作。一位生产线工人看到一个缺陷,然后拉扯安第斯绳,整个工厂停顿了下来,管理结束了,直到问题解决,生产线才重新启动。Google Andon Cord。这不是一个新概念。参见:startuplessonslearned.com/2008/09/…–
Christopher Mahan

4
@AndresJaanTack:当然,这取决于您的方法,但总的来说我不同意。至少在业务环境中,安排工作是一项业务决策- 包括错误修复。有时,新功能(或在特定日期发布)可能比修复(较小)错误更有价值-在这种情况下,必须推迟修正错误。在这种情况下,“立即修复错误”是不合适的,因为它会延迟更重要的工作。
sleske 2012年

106

您为什么要允许构建成功解决已知缺陷?

因为有时您有时间限制。或者该错误太小,以至于真的不值得将产品的交货时间推迟几天进行单元测试和修复。

另外,每次发现错误时有意破坏构建的意义何在?如果找到了它,请对其进行修复(或将其分配给要修复的人员),而不会打扰您的整个团队。如果您想记住要修复的错误,则需要在错误跟踪系统中将其标记为非常重要。


我明白您的意思,并且总体上我同意-但是在这种情况下,我们所谈论的是一个严重的错误,该错误已将其投入生产并被最终用户遇到:s
MattDavey 2012年

3
请参阅我的答案的第二段。
Arseni Mourzenko 2012年

8
我理解,我认为这是在您的第一段中总结的-并不是由开发人员来判断错误的严重性,还是由它来阻止问题,这才是更广泛的业务的决定。
MattDavey 2012年

4
问题是此错误的优先级是什么?现在可能是OMG修复,可能是的,这很烦人,我们应该在某个时候修复它,这可能是中间问题。但是,并非所有的错误都会在该范围内的同一位置发生。
Zachary K

55

有测试可以确保您不会(重新)引入问题。失败的测试列表不能替代错误跟踪系统。POV中有一些有效性,即失败的测试不仅表示错误,而且还表示开发过程失败(从粗心到识别不良的依存关系)。


20
“失败的测试列表不能替代错误跟踪系统” +1,这也是一个很好的观点:)
MattDavey 2012年

1
我建议您将回归单元测试作为修正的一部分(而不是更早)输入代码库。
yrk 2012年

6
@yarek:回归测试可以随时进入代码库,只是需要将其忽略,直到修复了该错误为止。我通常在诊断问题时开发它们,因为它们可以兼作调试辅助。
sleske 2012年

这是一个很好的例子,说明为什么“破坏体系”成为CI仅仅转变为“责备驱动的发展”的工作场所的有害部分。我参加了很多会议,PHB开始抱怨“粗心”,这就是为什么构建失败的原因。在这样的环境下,您几乎不会故意检查破坏构建的内容。否则,PHB会不高兴。破坏体形,穿上耻辱之心。多么糟糕的做法。
沃伦·P

@WarrenP,有时还存在其他问题,但请注意,粗心是构建失败的第一个原因。如果您知道某个东西破坏了版本,为什么还要签入?
AProgrammer 2012年

23

“中止构建”是指阻止构建成功完成。测试失败不会那么做。这表明该版本具有已知的缺陷,这是完全正确的。

大多数构建服务器会随着时间的推移跟踪测试的状态,并且会为自添加以来一直失败的测试分配不同的分类,而不是将其归类为回归(过去通过但不再执行的测试),并且还会检测修订的版本。发生了回归。


12
这并不总是正确的,通常团队将失败的测试视为失败的构建-实际上,我最近见过的大多数团队都这样做(这是典型的敏捷实践)。对于大多数敏捷团队来说,失败的测试就是您停止生产线的情况-整个团队都在攻击问题并解决了问题。我想我可以以您的帖子来表示,回复必须基于您的实践,在这种情况下,它是完全准确的。
Bill K

2
我总是认为测试失败意味着构建失败。
约翰·桑德斯

@JohnSaunders:但这不是什么意思。正如我在回答中所说的,它的意思是“内部版本已知缺陷”。
Ben Voigt 2012年

1
@ho说没有测试?你从哪里得到的?我的意思是,发现错误后的第一步不是阻止构建成功,而是创建详细的错误报告。修复错误后,首先应该有一个失败的单元测试。
约翰·桑德斯

1
立即创建失败的测试几乎没有问题。我只是不希望它签入将在构建时运行的测试集。我还希望修复该错误的开发人员能够忽略该测试。在我工作过的大多数地方,创建错误报告的人都不会创建单元测试。
约翰·桑德斯

16

我认为应该添加失败的测试,但不能明确地将其添加为“失败的测试”。

正如@BenVoigt在他的答案中指出的那样,失败的测试并不一定会“破坏构建”。我猜每个团队的术语可能会有所不同,但是代码仍然可以编译,并且产品仍可以通过失败的测试交付。

在这种情况下,您应该问自己,

测试意味着要完成什么?

如果存在测试只是为了让每个人都对代码感到满意,那么添加一个失败的测试只是让每个人都对代码感到不满意,似乎效率不高。但是,首先测试的效率如何?

我的断言是,测试应该反映业务需求。因此,如果发现“错误”表示未正确满足要求,则表明测试未正确或完全反映业务要求。

是要首先修复的错误。您不是在“添加失败的测试”。您正在更正测试以更准确地反映业务需求。如果代码随后未能通过这些测试,那是一件好事。这意味着测试正在发挥作用。

修改代码的优先级由企业确定。但是在确定测试之前,可以确定该优先级吗?为了使他们能够优先做出决定,企业应该了解确切的故障,故障的原因以及故障的原因。测试应表明这一点。

进行不完全通过的测试并不是一件坏事。它会产生大量已知问题,需要对其进行优先级排序和相应处理。但是,拥有无法完全测试的测试是一个问题。它质疑测试本身的价值。

换句话说,构建已被破坏。您要做的只是确定是否要引起注意。


1
您的断言是错误的,单元测试不一定直接映射到业务需求,而功能测试或端到端测试则可能正确,但是OP在谈论单元测试/ TDD。
约翰·布坎南

@JohnBuchanan:验证该软件的意图是什么?(也就是说,它符合要求。)如您所言,单元测试之外还有其他形式的测试。但是我看不到单元测试中的价值,而单元测试不能验证软件是否满足业务需求。
David

1
@JohnBuchanan-他没有说“测试反映了业务需求”,而是说“应该成为”。这是真的,但值得商bat。您声称这并非总是如此是正确的-有些人编写的单元测试未映射到业务需求-尽管(我认为)这样做是错误的。如果您想声称大卫的主张是错误的,则可以说些为什么。
达伍德·伊本·卡里姆

13

在我们的测试自动化团队中,我们检入失败的测试,只要它们是由于产品缺陷而不是由于测试缺陷而失败。这样我们可以为开发团队证明,嘿,他们打破了它。破坏构建的做法很不容易,但这与检查可完全编译但失败的测试并不相同。


4
我认为@MattDavey的想法是一个很棒的想法,过去我一直在主张。我一直遇到一道抵抗的石墙-“您绝不应该破坏建筑!”。人们似乎无法理解在这种情况下构建已被破坏的想法。令人遗憾的是,这只是一个好主意(自动测试和整洁的构造)已演变为一种货真价实的做法的情况,其信奉者知道规则但不知道原因。
汤姆·安德森

3
我想到的一个想法是,应允许QA团队(如果他们有足够的技能来编写测试),可以编写失败的bug测试并进行检入。优先于修复错误而不是添加功能,这是进行开发的正确方法。
汤姆·安德森

但是,这些不应是将在构建期间运行的单元测试。如果您的环境包含用于QA的测试管理系统(例如Microsoft Test Manager),那么可以肯定的是,应该添加一个或多个测试用例并将其链接到该错误,但这不会阻止构建成功-它将只是一个测试错误被认为是“完成”之前必须通过的情况。
约翰·桑德斯

7

编写一个您知道在修复该错误之前将失败的测试是一个好主意,这是TDD的基础。

破坏构建是一个坏主意。为什么?因为这意味着在修复之前,任何事情都无法继续进行。它实质上阻碍了开发的所有其他方面。

示例1
如果您的应用程序很大且有很多组件,该怎么办?如果其他团队以自己的发布周期来处理这些组件,该怎么办?强硬!他们必须等待您的错误修复!

示例2
如果第一个错误很难修复,而您发现另一个优先级更高的错误怎么办?您还会破坏第二个错误的构建吗?现在,您必须先修复两者,然后才能构建。您已经创建了人为的依赖项。

没有逻辑上的原因导致测试失败会停止构建。这是开发团队需要做出的决定(可能需要管理层讨论),权衡发布具有已知错误的构建的利弊。这在软件开发中很常见,几乎所有主要软件都发布时至少带有一些已知问题。


5

这取决于测试应该扮演的角色以及测试结果如何影响所采用的构建系统/过程。我对破坏构建的理解与Ben的理解相同,同时,我们不应该有意识地检入破坏现有测试的代码。如果这些测试“晚些”进行,则忽略它们只是为了减少不必要的破坏性,这可能是“好的”,但是我发现这种忽略测试失败(以便它们似乎通过)的做法相当令人不安(尤其是这样)对于单元测试),除非有一种方法可以将测试指示为红色或绿色。


为了记录,“除非有一种方法可以将测试描述为红色或绿色”,否则大多数记录都区分红色,绿色和被忽略的测试。至少JUnit和TestNG会这样做(它们报告“ xx测试,x失败,x被忽略”)。
sleske 2012年

@sleske那将是理想的选择,我只是想确保忽略失败不会自动变成成功
prusswan 2012年

不存在黄色建筑吗?(红色/绿色/黄色)在哈德逊/詹金斯,巡航控制系统以及其他所有大佬中?
沃伦·P

@Warren P当人们正确地忽略测试时起作用,但是有些人通过使它们
变成

5

当然,这取决于错误,但是通常,如果在手动或自动测试过程中未发现错误,则表明您的研究范围存在差距。我绝对会鼓励找出根本原因,并在问题之上打个单元测试用例。

如果计划在维护部门中进行热修复是生产问题,则还需要确保该修复程序可以在主线上运行,并且开发人员不能通过过度狂热的合并冲突解决方案错误地销毁该修复程序。 。

此外,根据您的发布策略,是否存在新近更新的单元测试可以帮助确认开发人员确实已解决了问题,而不仅仅是更改了问题((问题还是测试?),尽管这取决于对代码进行编码。在新的单元测试中正确的要求。


5

向构建中添加“知道失败”测试的一个问题是,您的团队可能会养成忽略失败测试的习惯,因为他们期望构建会失败。这取决于您的构建系统,但是如果失败的测试并不总是意味着“某些东西刚刚坏了”,那么就很容易对失败的测试给予较少的关注。

您不想帮助您的团队进入这种思维方式。

因此,我同意sleske的意见,您应该添加测试,但出于自动构建的目的,请将其标记为“忽略”,直到修复该错误为止。


1
与以前失败的测试相比,您的测试软件应该告诉您什么时候新损坏了。
Ben Voigt 2012年

4

虽然我认为您应该以某种方式“检入”该bug作为测试,以便在您对其进行修复时不会再次发生,并且以某种方式对其进行优先级排序,但我认为最好不要破坏构建(/测试) 。原因是随后的构建中断提交将隐藏在已损坏的测试之后。因此,通过为该错误检查破损的测试,您需要整个团队将工作放在一边以修复该错误。如果这种情况没有发生,那么您可能会导致无法进行此类跟踪的提交失败。

因此,我想最好将它提交为未决测试,并使其在您的团队中优先考虑不要进行未决测试。


4

另一个选择是将失败的测试检查到源代码管理系统中的单独分支中。根据您的实践,这是否可行。有时,我们会为正在进行的工作打开一个新分支,例如修复一个不重要的错误。

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.