持续集成的前提条件
持续集成不会独立地帮你修复构建过程。事实上,如果你在项目中期才做这件事的话,可能会非常痛苦。为了使持续集成能够更有效,开始之前,你应该先做好下面这些事情。
1.频繁提交
对于持续集成来说,我们最重要的工作就是频繁提交代码到版本控制库。每天至少应该提交几次代码。
定期地将代码提交到代码主干上会给我们带来很多其他好处。比如,它使每次的修改都比较小,所以很少会使构建失败。当你做了错事或者走错了路线时,可以轻松地回滚到已知的正确版本上。它使你的重构更有规则,使每次重构都是小步修改,从而保证可预期的行为。它有助于保证那些涉及多个文件的修改尽量不会影响其他人的工作。它让开发人员更敢于创新,用于尝试新的想法,而且一旦行不通,可以轻松地回滚到最近提交的一个版本上。它还会让你不时地停下来休息一下,伸展一下身体,有助于防止腕关节疼痛或肢体重复性劳损(RSI)。如果发生了严重的问题(比如误删了文件等),你也不会丢掉太多的工作成果。
前面我们特意提到过“要提交到主干”。很多项目使用版本控制中的分会技术来进行大型团队的管理。然而,当使用分支时,其实不可能真正地做到持续集成。因为如果你在分支上工作,那么你的代码就没有和其他开发人员的代码进行即时集成。那么使用长生命周期分支的团队恰恰面临着我们在本章开始时描述的问题。除了一些很有限的情况外,我们不推荐使用分支。
2.创建全面的自动化测试套件
如果没有一系列全面的自动化测试,那么构成成功只意味着应用程序能够编译并组装在一起。虽然对于某些团队来说,这已经是非常大的一个进步了,但是,假如能够有一定程序的自动化测试,会让你更有信息说:“我们的应用是可以工作的。”
单元测试用于单独测试应用程序中某些小单元的行为(比如一个方法、一个函数,或一小组方法或函数之间的交互)。它们通常不需要启动整个应用就可以执行,而且也不需要连接数据库(如果应用程序需要数据库的话)、文件系统或网络。它们也不需要将应用程序部署到类生产环境中运行。单元测试应该运行的非常快,即使对于一个大型应用来说,整个单元测试套件也应该在十分钟之内完成。
组件测试用于测试应用程序中几个组件的行为。与单元测试一样,它通常不必启动整个应用程序,但有可能需要连接数据库、访问文件系统或其他外部系统或接口(这些可以使用“桩”,即 stub 技术)。组件测试的运行时间通常较长。
验收测试的目的是验证应用程序是否满足业务需求所定义的验收条件,包括应用程序提供的功能,以及其他特定需求,比如容量、有效性、安全性等。验收测试最好采用整个应用程序运行于类生产环境的运作方式。当然,验收测试的运行时间比较长。一个验收测试套件连续运行一整天是很平常的事。
3.保持较短的构建和测试过程
如果代码构建和单元测试的执行需要花很长时间的话,你会遇到一些麻烦,如下所示。
大家在提交代码之前不愿意在本地环境进行全量构建和运行测试,导致构建失败的几率越来越大。
持续集成过程需要花太长时间,从而导致再次运行构建时,该构建会包含很多次提交,所以很难确定到底是哪次提交破坏了本次构建。
大家提交的频率会变少,因为每运行一次构建和测试,都要坐那儿等上一阵子。
理想情况下,提交前的预编译和测试过程,以及持续集成服务器上的编译和测试过程应该都能在几分钟内结束。我们认为,十分钟是一个极限了,最好是在五分钟以内,九十秒内完成是最理想的。十分钟对于那些惯于操作小项目的人来说,应该算是比较长的时间了,但对于那些经理过需要花数小时的编译的老前辈来说,却是非常短的时间。这段时间长度应该恰好能泡杯茶,快速聊几句,看一眼邮件,或伸展一下身体。
接下来的这个要求看上去恰好和上一个(即需要有全面的自动化测试集)相矛盾。但是,有很多技术可以帮助你减少构建时间。首先要考虑的事情是让测试执行得更快。XUnit 类型的工具,比如 JUnit 和 NUnit,可以提供每个测试运行时长的报告。找出那些运行较慢的测试,看看是否可以把他们优化一下,或者在确保同样覆盖率和信心的前提下缩短测试时间。这件事情应该经常做。
然而,有时候需要将测试分为几个阶段,那么如何规划阶段呢?首先将其分成两个阶段。第一个阶段用于编译软件,运行所有类级别的单元测试,并创建用于部署的二进制。这个阶段叫做“提交阶段”。
第二阶段应该利用第一阶段所生成的二进制文件进行验收测试、集成测试。加入你有性能测试的话,也要一并运行。利用现代持续集成工具,很容易创建这种分阶段的构建流程,它们能够同时运行多个任务,并将运行结果收集在一起,以便于很容易看到运行状态和结果。
提交阶段的这套测试应该在提交之前运行,而且在每次提交之后,在持续集成服务器上也要再运行一次。一旦提交测试套件通过了,就要马上运行验收测试的第二个阶段,但这个阶段可能会花更多时间。如果该阶段用时超过半小时,就要考虑使用高性能的多进程机器或者建立构建网格来并行执行这些测试。现代的持续集成服务器都能让这件事变得很简单。另外,有时候把一个简单的冒烟测试套件加入到提交阶段,也是非常有用的。这个冒烟测试套件应该执行一些简单的验收和集成测试,用于确保最常见的功能没有被破坏。加入这些基本功能被破坏了,就能得到很快的反馈。
4.管理开发工作区
对于保证开发人员的开发效率与明晰思路来说,开发环境的管理是特别重要的。当开发人员刚开始新任务时,应该总是从一个已知正确的状态开始。他们应该能够运行构建、执行自动化测试,以及在其可控的环境上部署其开发的应用程序,通常是在他们自己的开发机上。只有在特殊的情况下,才应使用共享环境开发。在本地开发环境上运行应用程序时,应确保所使用的自动化过程与持续集成环境中的一致,与测试环境中也是一样的,且生产环境中也是一样的。
达到这一目标的第一个先决条件就是细心的配置管理,不仅仅是管理代码,还包括测试数据,数据库的脚本、构建脚本和部署脚本,这些全部都要放在版本控制库中,且当编码开始时,应该以它们“最新的正确版本”作为起点。“最新的正确版本”是指那个在持续集成服务器上最近一次通过所有自动化测试的那个版本。
其次是对第三方依赖的配置管理,即那些开发中所用的库文件和组件。应确保库文件或组件的版本都是正确的,即它们的版本与你开发的源代码的版本是相互匹配的。有些开源工具可以帮助管理第三方依赖,最为常见的有 Manven 和 lvy。然而,使用这些工具时,你需要格外小心地确保配置这些工具,这样才能保证不必每次都将某些第三方依赖的最新版本重新下载到本地仓库中。
对于大部分项目来说,其所依赖的第三方库文件的版本不会经常发生改变,所以最简单的方法就是将这些库文件随你的代码一起提交到版本控制库中。
最后就是确保自动化测试(包括冒烟测试)都能够在开发机上运行。对于一个大型系统,我们可能需要在开发机上配置中间件,运行内存数据库或单用户数据库。这的确要花一定的功夫,但能够让开发人员于每次提交在自己的开发机上将应用程序运行起来,并在其上跑一遍冒烟测试,这可以大大改善应用程序的质量。事实上,一个好的应用程序架构的标志就是不需要费太大力气就可以让应用运行在开发机上。
搜索微信公众号:TestingStudio 霍格沃兹的干货都很硬核
评论