替代“通过/损坏的构建”指示器?


14

当在每次提交时执行测试的持续集成时,通常的最佳实践是使所有测试始终通过(也就是“不破坏构建”)。

我发现一些问题:

例如,不能通过创建与票证相对应的测试来帮助开源项目。我知道如果我向包含失败测试的开源项目提出“拉取请求”,则该构建将被标记为失败,并且该项目将不希望将其合并到其存储库中,因为这会“破坏构建”。

而且我不认为在您的仓库中测试失败是一件坏事,就像在跟踪器中遇到未解决的问题一样。这些只是等待修复的事情。

公司也是如此。如果使用TDD,则无法编写测试,提交并编写满足测试要求的逻辑代码。这意味着,如果我在笔记本电脑上编写了4-5个测试,则在休假前我无法提交它们。没有人可以收回我的工作。我什至不能与同事“共享”他们,例如通过电子邮件发送给他们。这也阻止了一个人编写测试,而另一个人编写模型。

话虽如此,我是否滥用/误解了构建过程/持续集成?在我看来,“通过” /“未通过”是一个过于狭窄的指标。

有没有办法使持续集成和TDD兼容?

也许有一个标准的解决方案/实践来区分“新测试”(可能失败)和“回归测试”(应该不会失败,因为它们曾经工作过)?


1
有一个指示器,显示最近一个小时(或大约一个小时)内失败的测试数量增加了(红色)还是减少了(绿色)。
Joachim Sauer

2
我不是TDD / ALM专家(因此请发表评论,而不是回答),但我认为您的问题可以通过私人分支机构/功能分支机构解决。您是否正在研究功能A?将其分支,在分支上(与同事)一起工作,完成后,将其合并到持续集成的中继中。
Avner Shahar-Kashtan

@JoachimSauer是的,但是这种度量标准是否在任何大型项目中标准化/使用?我试图了解为什么大多数项目(和CI工具)都以这种方式工作。
Matthieu Napoli

我认为“可能失败的测试”的正确标准不是“新测试”,而是“已知未解决问题的测试”。我可以看到这些测试有什么用处-我还可以看到那些测试在CI构建中没有用处,因为它们会污染那里的测试通过/失败的含义(您只想运行某人实际花费时间的测试)让他们通过)。
Joris Timmermans

确实是@MadKeithV
Matthieu Napoli

Answers:


12

我知道您要去哪里,但是这些类型的问题通常可以通过其他方式解决。有一个很好的理由说明为什么这是标准协议。如果有人提交了无法编译的代码,那么更新他/她的代码的每个人都会拥有一个不能编译的程序。这包括目前正在从事完全不同的工作并且以某种方式发现自己处于需要等待才能编译和测试其工作内容的程序员的程序员。

标准协议是,即使编译完成,您也可以提交更改,甚至可以完成甚至不完整的工作,以便程序员在必要时每天可以更新其代码。

但是,我仍然看到您的意思。有时您想要提交以仅保存您的代码。为此,大多数源存储库都支持分支。这使您可以创建一个私有分支,在不打扰其他分支的情况下进行处理,然后在工作完成后合并到中继中。这使您可以在需要时进行提交,而不会导致导致构建中断的任何反弹。

如果不合适,GIT允许您将(推送)到本地计算机上的存储库中,但是可以想象该存储库可以在任何地方。您可以为可能的部分/不完整的工作创建一个存储库,并为完成的工作创建另一个存储库,然后您可以在该存储库上添加每晚构建。

再说一次,我不能太强调重要性。 永远不要将损坏的代码提交到中继! 您的贡献不会影响其他程序员的工作。

编辑

我看到您打算破坏测试,但以我的拙见,两者之间几乎没有区别。测试的全部重点是确定程序的特定方面是否通过或失败。如果它总是失败并且您什么都不做,那么在传统的单元测试用法中,该测试将无济于事。如果您使用它执行某些其他指标(如果一个这样的测试失败),则不一定需要提交“失败”的提交,那么我强烈建议您找到另一种方法来执行相同的操作。

否则,您可能会冒风险,那就是永远不要考虑该测试,或者如果它导致您的构建失败,那么您的其他程序员将忽略失败的构建。对于程序员来说,意识到他们破坏了构建的重要性比执行不提供真正洞察力并可能导致不良实践的测试更为重要。


1
确实,您对主题分支提出了意见。但是我从来没有在谈论提交损坏的代码,只是在测试失败。例如,即使我不知道如何解决问题,我也可以通过为入场券创建测试来帮助一个开源项目。这为维护人员节省了一些时间。
Matthieu Napoli

如果我与您在同一个项目上,并且您上载了失败的测试,那么我现在有一个包含失败测试的版本。由于该功能尚未实现,我可能最终删除了您的测试,或者决定实现该功能,最终踩了您的代码,浪费了时间。如果有这样做的文化,可以避免这种反应,但是每个人都会这样做,因此即使您的所有测试都通过了,也并非我所有的人都会这样做。在这种情况下,构建将始终具有失败的测试。我没有上升空间。
迈克尔·肖

the build would always have failing tests恰好!但这是一件坏事吗?我们唯一的指标是“构建是否被破坏”,但是您的代码可能充满了已知的错误,因此,除了没有回归之外,这实际上并不意味着任何东西。在一个完美的世界中,每个跟踪器问题都需要测试(复制比修复容易)。因此,好处是可以看到35个测试/所有测试的70%通过了,Branch-A将其提高到40个测试(80%)而没有回归,而Branch-B具有回归。今天您只能说Master和Branch-A正常,而Branch-B坏了。
Matthieu Napoli

@Matthieu我明白你在说什么。听起来您需要一个特殊的类别,或者说“嘿,如果此测试失败,就可以了。我们知道。但是我们仍然希望它能够运行,如果通过了,那就更好了,我们应该删除特殊类别,因为我们现在在乎它是否会断裂”
Earlz 2013年

@Earlz就是这样!我想知道的是“它是由某人在某个地方完成的吗?并且有支持该工具的工具(CI和单元测试库吗?”),因为如果我仅使用经典的CI和单元测试工具对这些测试进行分类,那么构建将始终无论如何还是失败,并且我不会看到失败的测试之间的区别,所以它不会有用:/
Matthieu Napoli

4

给定一个主分支测试失败,您如何确定(没有将该列表与以前的版本进行比较)您没有引入错误?

仅仅跟踪失败测试的数量是不够的:您可以修复一个测试,然后破坏另一个测试。而且,如果您正在度假,那么其他人会发现失败的版本并不清楚。

始终保持主分支清洁,绿色。在分支机构工作。将分支机构置于CI下,进行单独的工作,并对心脏的内容进行失败的测试。只是不要打破主人。

如果分支的审核员通过所有测试,则仅使其合并。(更强烈地说:如果将分支合并到master中的结果通过所有测试,则审阅者只能合并您的分支!)


2
Simply tracking the number of failing tests is insufficient这不是唯一可能的指标。例如:Branch-A improves it to 40 tests (80% passing) with no regression。没有回归意味着先前通过的测试始终会通过。简而言之,只要测试从未通过,就可以允许它失败。在我看来,通过限制主分支中的失败测试,​​我们错过了一些好东西。(当然,这需要工具以不同的方式工作:单元测试,CI等)
Matthieu Napoli

我仍然坚持我的观点:大师应该永远是绿色的,因为它清晰明确。一定要在功能分支中使标记测试失败。CI可以随时提醒人们注意未解决的错误。
Frank Shearar

我认为Matthieu提出的对“绿色”的定义稍有不同,而不偏离始终是绿色的主人。对我来说,这没有意义,这不是很明显-当然,它需要一些并非完全无关紧要的工具来进行跟踪。(需要回滚使测试通过的变更吗?如果这意味着状态突然变成红色,
那就很不幸了

NUnit具有忽略测试的概念。那可能是另一种选择:它们不会运行,因此不会失败,但是仍然被报告为被忽略。
Frank Shearar

2

有一些方法可以解决您的问题,而又不会丢掉关于持续集成的广为人知和接受的实践。

我将从提交与故障单相对应的“损坏测试”的问题开始。一种解决方案是创建一个或多个暴露问题的破坏性测试,然后实际解决问题,以便可以将它们合并回主代码行。第二种解决方案是测试失败,但是使用某种类型的ignore标志,这样它们就不会真正运行并破坏构建。可能添加注释或特殊注释,这很明显这是对的失败测试Ticket#N。还要在票证本身上添加一条注释,该注释引用创建的正在等待被忽略和运行的测试。这将有助于检票的人,但对于参加考试的人也不会构成危险。

接下来是TDD的下一个问题。TDD是关于编写一个小型测试,然后编写一小段代码以使该测试通过的。然后继续进行迭代,直到有了一个小的功能模块。我认为,如果您编写4-5个测试,然后去度假,则可能做错了。您可以与某人配对程序,一种方式是编写测试,另一种则编写相应的代码。但是,在准备好提交完整的模块之前,您不应使用主代码行存储库在彼此之间共享此代码。正如其他人所建议的,共享分支将在那里解决您的问题。

试图打破持续集成的口号可能会导致出乎意料且令人恐惧的道路。例如,在这种类型的环境中代码覆盖率意味着什么?开发人员怎么会觉得该系统有很多破碎的Windows?一个人如何进行更改,运行测试并知道他们实际上是在破坏新的东西,还是仅仅是旧的东西?


您不需要任何工具即可与与之配对的人共享-只需交出键盘即可。如果您使用的是其他计算机,那么这没什么问题,这不是“配对编程”。
Christopher Creutzig 2013年

1

我认为您的根本问题是,您将测试结果包含在构建中。虽然显然有些人同意您,但其他人则不同意。不构建时发生构建中断。如果不是没有错误就不会构建。

考虑一个大型项目,例如Windows或Linux,甚至是Firefox之类的项目-您认为它们没有错误吗?当然不是。现在这些项目都没有进行TDD,但这确实无关紧要-TDD不会改变两个基本事实:存在错误,并且需要时间来修复它们。一个项目(无论是否开放源代码)都不能浪费在低优先级bug上的时间。KDE最近有一个已修复十年的错误。您什么时候最后一次听到有人说“我很高兴我们等了十年才能交付我们的项目”?

从某种意义上说,TDD可能使错误的发布更加容易-因为您对缺陷的含义有了更好的了解。如果您可以精确地定义导致该错误的原因,则可以为衡量该错误的成本奠定良好的基础。

我的建议是找到一个绿色项目中不介意红色的项目。


1
 > a common best practice is to have all the tests passing (green) at all times.

我更喜欢所有测试都不会失败(不是红色)。

使用这个稍微不同的定义,您还可以定义

  • 尚未实现(如果存在NotImplementedException,则nunit中为灰色)
  • 通过将测试标记/注释为已忽略(黄色)而已知为“ =“需要执行”

我将它们检入存储库中,您的连续构建没有中断,因此有效。


0

您可以考虑两个不同的CI构建“概念”。

  1. 常规CI生成。常规CI构建应仅编译并运行已为其编写代码以使其通过的那些测试,这样,测试通过/失败的CI报告是针对代码先前接受状态的明确,明确的回归指示。
  2. “未来” CI构建。此版本仅编译并运行那些没有专门编写代码以使其通过的测试。进行这种测试可能有几个原因:

    • 可以从问题跟踪器添加针对特定故障案例的测试,但尚未尝试修复。即使没有修复,已经对问题进行了编纂,运行的测试显然很有用。

    • 为尚未实现的新必需功能添加了测试。

    • 通常,知道如何测试故障或功能比知道如何实现功能或修复要容易得多,通过将测试提交给源代码控制来分离两个步骤对于确保没有信息丢失很有用。

就像在“标准” CI中一样,在常规开发方案中,团队仅查看常规构建的每日构建结果。

团队还可以密切关注“未来” CI版本中测试用例的演变-特别是查看对常规CI所做的任何更改是否实际上解决了“未来” CI版本中的问题,这可能表明存在重要意义。基本问题或设计改进。

最后,如果团队成员有多余的时间可以解决“未来”中的一个问题,并且如果他们成功,则将其迁移到“常规”(同时更新问题跟踪器状态)。


0

而且我不认为回购中的测试失败不会有坏事,就像跟踪器中存在未解决的问题一样。这些只是等待修复的事情。

问题不在于测试失败,而是一个简单的,没有上下文的回归指标。Aka:作为一名开发人员,我可以检查一个指标并知道我是否引入了回归或破坏代码。

当您介绍“软”故障的概念时(没关系,我们正在努力/尚未实现/我们正在等待新版本/一旦其他版本修复后它将再次通过),您需要每个可能运行或查看测试以了解预期状态的人。在足够大的团队中,哪个将按小时进行更改:您的指标变得毫无意义。在较小的情况下(例如团队私有集成测试),我认为这就像技术债务一样,还可以-只需进行管理即可。

大多数工具的地址“绿色/通过”反映了预期的结果-而不是代码在起作用:

  • 健身具有预期失败的概念。
  • JUnit具有@Ignored / @Test(expect =)
  • 黄瓜处于“尚未实施”(或所谓的状态)状态

这些都有自己的问题(您如何区分“是的,我们知道它已损坏,正在解决”和“正确的行为是一个例外”),但它们会有所帮助。


0

我使用跳过的测试。

在我使用的特定单元测试框架中,可以引发SkipTest异常。该测试实际上并未运行,并且其失败不会破坏构建。但是,我可以看到跳过的测试的数量,并查看在该区域是否有工作要做。

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.