持续交付提交阶段的最佳实践

持续交付提交阶段的最佳实践

提交阶段的主要是从某个人向版本库中提交了一次变更后,持续集成服务器发现此次变更,并且将其代码变为制品,并输出到制品库
中并生成报告的过程。

提交阶段中,持续集成服务器的主要工作如下:

  • 编译(如果需要的话)
  • 创建能部署在所有环境中的二进制包(如果使用需要变异的语言,则包括编译和组装)。
  • 执行必要的分析,检查代码库的健康状况。
  • 创建部署流水线的后续阶段需要使用的其它产物(如:数据库迁移或者测试数据)。

建立高效提交阶段的原则和实践如下:

提交阶段的原则和实践

提供快速有效的反馈

提交测试的主要原因是:

  • 由于语法错误导致编译失败。
  • 由于语义错误导致一个或者多个测试失败。
  • 由于应用程序或的配置或者环境方面的问题引起的。

引入错误后,越早发现他,就越容易修复他。

如果开发人员频繁的提交修改,则每次产生的变更都会比较小。如果部署流水线能够快速发现失败(最好是在提交阶段)的话,那变更的范围就仅限于该开发人员自己修改的代码。在此时,修复那些发现的问题,要比修复那些哟后续运行大量测试的阶段发现的问题简单得多。

在采纳持续集成实践的早期,常见的错误是对:”有问题就尽早使其失败“是按照字面意思理解,即,一旦发现错误,就让构建立即失败,这几本上是正确的,但优化的过头了。我们一般会将提交阶段分按照项目而异为一系列的任务,比如:编译、运行、单元测试等。只有在某个错误让提交阶段的其他任务无法执行的时候,我们才会让提交阶段停下来,如:编译错误,否则就直接让提交阶段全部运行完后,才汇总所有的无哦呜和失败白报告,以便可以一次性修复他们。

何时令提交阶段失败

传统上讲,出现以下错误之一时,就应该让提交阶段失败,即,出现编译错误、测试失败或者环境难问题,否则就应该让提交阶段成功通过并报告一切OK。但是,这样的话,无法判断代码质量等问题,有如下的实践:

如果某次构建时,编译告警的数量比前一次增多或者灭有减少,则让提交阶段失败(渐进式实践)

如果重复代码的数量超出了某个实现约定的限制,或者代码质量的其他度量项目不符合约束条件时,就让提交阶段失败。

无论如何,提交阶段一旦失败,则交付团队就要立即停止手上的工作,把它修复。如果全团队尚未就某个原因达成一致,就不要让提交测试失败,否则,持续集成会失去应有的作用。

精心对待提交阶段

要不断努力地改进提交阶段脚本的质量、设计和性能。一个高效、快速、可靠的提交阶段是提高团队生产效率的关键,所以只要花点儿时间和精力在这上面,让它处于良好的工作状态,就会很快收回这些投入成本。

让开发人员也拥有权限

如果必要的话,即使是很普通的变更(比如增加新的库文件和配置文件等)
也都应该由一起工作的开发人员和运维人员来执行。这类活动不应该由构建专家完成,除非是在项目初期团队刚开始建立构建脚本时。

不能低估专家们的专业知识,但他们的目标应该是建立并使用良好的结构、模式和技术,并将他们的知识传授给交付团队。一旦建立了这些基本规则,只有对脚本结构进行较大修改时才需要他们的专业知识,而日常构建维护工作不应该由他们来做。

对于非常大的项目,有时候会需要一个环境专家或构建专家全职投入。但是,根据我们的经验,最好还是把它看做是为了解决某个棘手问题的权宜之计,令开发人员和专家在一起工作,以便知识可以传递到交付团队。

开发人员和运维人员都必须要习惯构建系统的维护工作,而且要对其负责。

在超大项目团队中指定一个构建负责人

在小团队或只有二三十人的团队中,自组织就可以了。如果构建失败了,通常很容易在这种规模的团队中确定谁(一位或多位负责人)
该负责修复它,如果他没进行修复的话则提醒一下他,如果他在进行修复,就帮他一下。

但在大团队中,这并不总是一件容易的事。此时,让某个(或多个)
人扮演构建负责人的角色是必要的。他们不但要监督和指导对构建的维护,而且还要鼓励和加强构建纪律。如果构建失败,构建负责人要知会当事人并礼貌地(
如果时间太长的话,不礼貌也没问题)提醒他们为团队修复失败的构建,否则就将他们的修改回滚。

这个角色能起作用的另一种情况是,当团队刚开始接触持续集成时。在这样的团队中,构建纪律还没有建立起来,有个人能不断提醒大家,会令事情走向正轨。

构建负责人不应该是由固定的人担任。团队成员应该轮流担当,比如每星期轮换一次。这个纪律不错,能让每个人都学到一些经验。无论怎么说,想一直做这项工作
的人还是不多的。

提交测试套件的原则与实践

避免用户界面

根据定义,用户界面是用户最容易找到缺陷的地方。这让大家自然而然地想到, 要把测试焦点放在用户界面上,这有时还会吃掉其他测试的成本。

然而,对于提交测试来说,我们建议根本不要通过用户界面进行测试。用户界面 测试的困难来自两方面。首先,它会涉及很多组件或软件的多个层次。这样是容易出
问题的,因为要花很多时间和精力去准备各种各样的组件或数据,才能让测试运行起 来。其次,用户界面是提供给用户手工操作的,而手工操作的速度与计算机操作的运
行速度相比,是相当慢的。

如果你的项目或所用技术可以避免这两点的话,那么通过用户界面创建单元级别 的测试可能也是值得的。然而,根据我们的经验,用户界面测试经常出问题,通常最
好由部署流水线的验收测试阶段处理。

使用依赖注入

依赖注入(或控制反转)是一种设计模式,用于描述如何从对象外部建立对象间的关系。显然,只有在使用面向对象语言时才能用上它。

避免使用数据库

首先,这种测试运行得非常慢。当想重复测试,或者连续运行几次相似的测试时,这种有状态的测试就是个障碍。其次,基础设施准备工作的复杂性令这种测试方法的建立和管理更加复杂。最后,如果从测试中很难消除数据库依赖的话,这也暗示着,你的代码在通过分层进行复杂性隔离方面做得不好。

在单元测试中避免异步

在单个测试用例中的异步行为会令系统很难测试。最简单的办法就是通过测试的切分来避免异步,这样就能做到:
一个测试运行到异步点时,切分出来的另一个测试再开始执行。

使用测试替身

在现实使用中,模拟技术会节省人们的很多精力。而且,它还能很好地把第三方的代码与你要测 试的代码分隔。当那些交互需要进行开销很大的远程通信或使用重量级的基础设施时,
它的作用是非常显著的。 最后,与需要组装所有的依赖和状态相比,使用模拟技术的测试运行起来通常是 非常快的。模拟技术有很多益处,我们强烈推荐使用。

最少化测试中的状态

设法让测试中的这种对状态的依赖最小化。你可能无法从根本上消除它,但为了运行测试,持续关注“如何降低要构造的测试环境的复杂性”是合理的。如果测试变得越来越复杂,很可能是由于代码结构问题引起的。

时间的伪装

时间问题是自动化测试需要面对的问题,原因有以下几个。你的系统可能需要在 每天晚上八点触发一个处理过程,也可能在启动下一步前要等上500毫秒,也可能要在
每个闰年的二月二十九号做一些特殊的处理。

如果你将这些时间和真正的系统时间绑定的话,这些情况处理起来可能会有点儿 棘手,且对单元测试策略说,很有可能是灾难性的。

对于所有基于时间的系统行为,我们的做法是将对时间的请求抽象到一个你能够控
制的类中。通常,我们使用依赖注入把用到的系统时间行为注入到包装类中(wrapper)。

通过这种方法,我们就可以为Clock这个类的行为进行打桩或模拟,或做一些我们认为合理的抽象。在我们的测试中,如果我们能设定当前是闰年,或要延时500毫秒的话,那么它就完全在我们的控制之下了。

蛮力

首先,将它分成多个套件,在多台机器上并行执行这些套件。时新的持续集成服务器都有“构建网格”功能,直接支持这种做法。
记住,计算能力是廉价的,而人力是昂贵的。及时得到反馈比准备几台服务器的成本要有价值得多。第二招儿就是,作为构建优化过程的一部分,将那些运行时间比较长且不经常失败的测试放到验收测试阶段运行。然而,需要注意的是,这会导致需要更长的时间才能知道这些测试是否失败了。

持续交付提交阶段的最佳实践

https://www.borgor.cn/posts/6a30ca1b.html

作者

Cyrusky

发布于

2019-07-14

更新于

2024-11-18

许可协议

评论