为什么要在CI服务器上运行单元测试?

当然,当有东西要掌握时,开发人员已经在之前运行了所有单元测试,并修复了新代码可能发生的任何错误。这不是单元测试的重点吗?否则,他们只会提交已损坏的代码。

评论

我们的开发人员不允许致力于掌握。他们推送到功能分支,然后CI服务器与master合并并运行测试。如果成功,则更改将合并到主服务器。因此测试失败的代码不能放在主控上...

@BoristheSpider-确实非常好的工作流程。母版应始终保持理智,最好在每次合并时自动部署到临时环境中以进行内部质量检查和测试。

“当然,当某些事情要掌握时,开发人员已经在运行所有单元测试,并修复了新代码可能发生的任何错误。”您生活在哪个幻想世界中?

在某些行业中,重要的部分不仅是对代码运行测试,而且还对二进制文件运行测试。在CI输出上运行测试意味着您可以保证所交付的产品能够正常工作,因为客户收到的确切二进制文件就是通过所有测试的二进制文件。这听起来很琐碎,但有时可能会产生影响(我见过的就是混淆;在复杂的项目上,或者奇怪地进行设置,可能会导致混淆版本中的问题,而干净版本中没有)。 br />
“当然,当某些事情要掌握时,开发人员已经在运行所有单元测试,并修复了新代码可能发生的任何错误。” ...不确定是否严重

#1 楼


当然,当某些事情要掌握时,开发人员已经在运行所有单元测试,并修复了新代码可能发生的任何错误。


或者不是。发生这种情况的原因可能有很多:


开发人员没有纪律来做到这一点
他们忘记了
他们没有承诺一切并推送了一个不完整的提交集(感谢Matthieu M.

他们只运行了一些测试,但没有运行整个套件(感谢nhgrif)
他们在合并之前在分支上进行了测试(感谢nhgrif * 2)


但是真正的重点是在不是开发人员机器的机器上运行测试。配置不同的机器。

这有助于捕获排除测试和/或代码取决于开发人员特定的东西(配置,数据,时区,语言环境等)的问题。

CI构建运行测试的其他充分理由:


在除主要开发平台之外的其他平台上进行测试,这可能会使开发人员难以进行测试(感谢TZHX)
接受/集成/端到端/真正长时间运行的测试可能在不会运行的CI服务器上运行通常在开发人员工具箱上运行。 (感谢Ixrec)
开发人员可能会在推送/提交之前进行一些微小的更改(认为这是安全的更改,因此无法运行测试)。 (感谢Ixrec * 2)
CI服务器配置通常不包括所有开发人员工具和配置,因此更接近生产系统
CI系统每次都从头开始构建项目,这意味着构建是可重复的
库更改可能会导致下游问题-CI服务器可以配置为构建所有相关的代码库,而不仅仅是库一个


评论


其他常见原因:1)CI服务器可能会运行高级集成/验收测试,而这对于开发人员来说总是花费很长时间。 2)开发人员确实运行了它们,然后做了一个微小的更改,然后才敦促他们确定不会破坏任何东西,但是我们希望确定。

– Ixrec
16年1月27日在13:34

对依赖项的更改通常也会同时运行所有下游构建。如果开发人员所做的更改使下游中断,则在修改库时不容易看到(例如,将基础数据类型从SortedSet更改为HashSet(仅提供Set的约定),而下游人员则错误地假设:集已排序)。如果不在CI服务器上运行(下游)测试,则该错误会持续一段时间。

–user40980
16 Jan 27 '14:10

@MichaelT好抓住。这实际上是这些天我们超过90%的CI失败的原因,不确定我是怎么忘记的...

– Ixrec
16年1月27日在15:14

同样,在CI环境中运行它们通常意味着您从头开始设置项目,以确保构建是可重复的。

– mgarciaisaia
16年1月27日在18:54

同样,可以提交两项更改,这些更改可以分别测试,但可以合并在一起(例如,其中一项删除未使用的API,另一项开始使用它)。

–西蒙·里希特(Simon Richter)
16年1月27日在20:20

#2 楼

作为一个在提交源代码管理之前不会运行所有集成和单元测试的开发人员,我将在这里提出自己的辩护。

我将必须构建,测试并验证应用程序可以在以下环境中正确运行:


带有Visual Studio 2008编译器的Microsoft Windows XP和Vista。
带有Visual Studio 2010编译器的Microsoft Windows7。


哦,并且每个MSI都会生成。


RHEL 5和6分别具有4.1和4.4(类似CentOS)


7很快。 Woop-de-woop。




带有GCC的Fedora工作站最新的三个版本。
Debian(以及类似Ubuntu的衍生版本)的最新三个版本。
最近三个最新版本的Mac OSX。


以及软件包(rpm,dmg等)



添加在Fortran(具有Intel和GNU编译器),Python(以及不同版本的OS)和bash / bat脚本组件中,我想您会发现事情呈螺旋状

所以我必须拥有16台机器,每天只需要运行几次测试。仅为此管理基础结构,这几乎是一项全职工作。我认为几乎所有人都会同意这是不合理的,尤其是将其乘以项目中的人数。因此,我们让CI服务器完成工作。

单元测试不会阻止您提交损坏的代码,它们会告诉您是否知道您已损坏了某些内容。人们可以说“单元测试应该是快速的”,然后继续讨论原理,设计模式和方法论,但是实际上有时候让我们为重复性,单调任务设计的计算机更好地做到这一点,并且只有在它们参与的情况下,它们才会更好告诉我们他们找到了一些东西。

评论


单元测试测试代码而不是配置。如果添加一个新测试并将其扔到墙上而没有先在本地运行它,那将是非常不明智的事情。

–罗比·迪(Robbie Dee)
16年1月27日在15:18

@RobbieDee恐怕看不到你的意思?我建议不要在没有本地测试的情况下创建新测试,或者只是在没有自己进行测试的情况下就盲目地将事情提交给源代码控制,而我会在自己的计算机上运行测试-但是“配置”的确需要进行测试以确保行为一致,并且当开发人员仍在考虑该问题时,最好相对快地执行此操作,而不是在主要使用Mac的团队醒来四千英里并更新其副本时发现问题。

– TZHX
16年1月27日在15:29

@RobbieDee我想说的是,如果TZHX可以在本地运行所有测试,但是他们不能。由于TZHX无法进行,因此他们在本地运行一些测试(例如,那些可以在其开发系统上运行并且与更改后的代码足够短或最相关的测试),然后让整个电池在CI系统上运行。相当合理。

–muru
16 Jan 27'23:52

@RobbieDee:他相信单元测试。因此,他在Macbook air上对其进行了测试,然后通过并签入。运行Red Hat,Solaris和Windows的CI服务器将再次运行这些测试。知道您测试的内容也可以在生产平台上使用,这不是很好吗?

– slebetman
16年1月28日在7:27

@RobbieDee:我经常编写特定于特定平台上特定编译器的单元测试。考虑例如一个使用AMD(Intel竞争对手)特定CPU指令的图形子系统,该指令仅在g ++(GNU C ++编译器)4.5版或更高版本上可用,但是我碰巧在Atom CPU和ICC(Intel C ++编译器)上工作。每次在该机器上运行AMD / g ++ 4.5-tests都是胡说八道,但这是要在发布之前进行测试的代码。再加上我自己的独立于CPU的代码,必须对其进行正确的互操作性测试。当然,有VM和仿真器,...

–菲涅耳
16年1月28日在14:41

#3 楼

除了出色的Oded答案:



您还可以测试存储库中的代码。它可能会在您的计算机上与您的文件一起使用...您忘记提交了。它可能取决于没有创建脚本(例如,在liquibase中),一些配置数据或属性文件的新表。

您可以避免代码集成问题。一个开发人员下载最后一个版本,创建单元和集成测试,添加代码,在其计算机上通过所有测试,提交并推送。另一个开发人员也做了同样的事情。两种更改本身都是正确的,但是合并时会导致错误。这可能是存储库合并,或者仅仅是未将其检测为冲突。例如。 Dev 1删除完全不使用的文件。开发人员2将对此文件进行编码,并在不进行开发人员1更改的情况下进行测试。

,您将开发一个脚本以从存储库自动部署。拥有通用的构建和部署脚本可以解决许多问题。一些开发人员可能添加了并非所有人共享的lib或编译选项。这不仅节省了您的时间,而且更重要的是,它使部署安全且可预测。此外,您可以在存储库中回到2.3.1版本,并使用与此版本兼容的脚本来部署此版本。它包括数据库对象,例如视图,存储过程,视图和应进行版本控制的触发器。 (否则您将无法返回到可行的版本。)

其他测试:如集成,性能和端到端测试。这可能很慢,并且可能包括Selenium等测试工具。您可能需要具有真实数据库的完整数据集,而不是模拟对象或HSQL。

我曾经在一家公司工作,由于合并和部署过程,该公司在部署方面存在很多错误。这是由于一个奇怪的专有框架导致测试和CI变得困难。发现无法在开发中完美使用的代码并没有直接投入生产,这不是一个快乐的经历。

评论


是的,只是忘记提交某些更改是很常见的。我会说忘记“ svn添加”新文件,因此忘记以后提交它们是获得自动构建失败的最流行的方法。

–锋利的牙齿
16年1月28日在7:28

#4 楼

您会以为不是吗-但是开发人员是人类,他们有时会忘记。

此外,开发人员经常无法提取最新代码。他们的最新测试可能运行良好,然后在签入时,其他人做出了重大更改。

您的测试也可能依赖于本地(未签入)资源。

如果您认为以上所有内容都是荒谬的,那么CI之上(至少在TFS上)有一个称为Gated的级别,该级别的测试失败被搁置并且不致力于代码库。

评论


我看到了更多糟糕的事情,我忘记了我愿意承认的CI失败。

–丹在火光中摆弄
16年1月27日在15:10

@DanNeely公平地说,它会让构建经理踢屁股,因为您忘了告诉他/她一些事情... :-)

–罗比·迪(Robbie Dee)
16年1月27日在15:12

这就是我喜欢CI的原因之一。寻找并修复自己的糟糕比让别人找到适合您的好得多。

–丹在火光中摆弄
16 Jan 27 '15:14



#5 楼


当某些东西提交给master时


我通常将CI设置为在每次提交时都运行。在测试分支之前,分支不会合并到master中。如果您依赖在master上运行测试,则将打开一个窗口以破坏构建。

在CI机器上运行测试与可重现的结果有关。由于CI服务器具有从VCS提取的已知干净环境,因此您知道测试结果是正确的。在本地运行时,您可能会忘记提交一些必需的代码以使其通过,或者忘记使用未提交的代码使它们在失败时可以通过。

通过运行不同的套件,还可以为开发人员节省时间。同时进行并行测试,尤其是在某些慢速,几分钟的测试中,每次更改后都不太可能在本地运行。

在我目前的工作中,我们的生产部署是通过CI通过所有测试的。除非通过脚本,否则部署脚本将阻止部署。这使得不可能意外地忘记运行它们。

CI作为工作流的一部分,也减轻了开发人员的负担。作为开发人员,您通常会为每一个更改运行一个linter,静态分析器,单元测试,代码覆盖率和集成测试吗? CI可以完全自动且无需考虑-减少决策疲劳。

评论


您不应该真正进行缓慢的单元测试-这违反了FIRST原则。

–罗比·迪(Robbie Dee)
16 Jan 27 '13:33



@RobbieDee:我认为通常CI服务器运行所有测试,而不仅仅是单元测试。

– RemcoGerlich
16年1月27日在13:35

@RobbieDee:理论上所有单元测试都是快速的。实际上....无论如何,CI可以并且应该运行所有测试-棉绒,静态分析,单元测试,集成测试。

–丹妮丝
16年1月27日在13:39

@RobbieDee显然,具体的配置因团队而异。即使构建需要花费几分钟,通常也可以并行运行多个构建。给定一个单一的代码库,这可能是一个更大的缺点,但IME并不是障碍。

–丹妮丝
16年1月27日在13:50

@RobbieDee我认为这更多地取决于您的体系结构。我已经看到它适合80左右的工程团队使用,但这是针对产品领域的明确定义的子团队。

–丹妮丝
16 Jan 28'在3:42

#6 楼

等到掌握一些东西时,开发人员应该已经运行了所有单元测试……但是如果没有,该怎么办?如果您不在CI服务器上运行单元测试,那么直到其他人将所做的更改拉到他们的计算机上并发现测试刚刚在他们身上中断后,您才能知道。

此外,开发人员可能犯了一个错误并引用了特定于其计算机的本地资源。当他们签入代码并且CI运行失败时,该问题将立即被识别并可以纠正。

#7 楼

假设(与其他答案相反)开发人员的纪律性很强,并且在提交之前进行了单元测试,可能有以下几个原因:


运行单元测试可能需要很长时间才能进行一些特殊的设置。例如,使用内存检查器(如valgrind)运行单元测试可能需要更长的时间。尽管所有单元测试都通过了,但是内存检查可能会失败。
对于某些特殊设置,结果并不那么重要-例如,运行单元测试以检查代码覆盖率需要特殊的编译标志。对于普通开发人员而言,代码覆盖范围并不是那么重要-对于谨慎的人来说,代码保持一定的质量(例如团队领导)更为重要。


#8 楼

可以想象这样的情况:更改A不会破坏测试,而更改B不会破坏测试,但是A和B一起可以破坏测试。如果A和B由不同的开发人员完成,则只有CI服务器将检测到新错误。 A和B甚至可能是同一更长句子的两个部分。

想象一下由两个机车A和B驾驶的火车。也许一个绰绰有余,这就是适用的解决方法。但是,如果应用这两个“修复程序”同时删除了这两个“修复程序”,则火车将不会移动。

#9 楼

让我们问一个等效的问题:


为什么要在CI服务器上构建代码?
之前已经构建了代码,并修复了新代码可能发生的任何错误
。这不是构建代码的重点吗?
否则,他们只是提交了损坏的代码。



执行CI的原因有很多,但主要是CI的目的是要了解一段时间后代码的状态。这样做的主要好处(是从几个中受益)是,我们可以找出构建中断的时间,找出破坏它的原因,然后修复它。

如果代码从未中断,为什么要这样做我们甚至使用CI?要交付构建以进行测试,每晚构建就足够了。