持续集成(CI)

引子html

  记得刚加入趋势开始开发工做的时候曾被告知,趋势有一套auto build的系统,会天天夜里自动把当天check in的代码进行构建,生成QA可测试的build。每一个RD都得当心提交code,由于项目结束的时候会看auto build的失败率。但是构建失败老是在所不免,尤为是每次要提交candidate build给QA作full cycle测试时,老是在最不应发生的时候发生最不可能发生的事情,至今我还记得为了按时出一个合格的candidate build,熬夜等build的经历。python

  Martin Fowler大师在2000的一篇文章中,最先提出了Continuous Integration(CI,持续集成)的概念。此后,CI做为软件开发的最佳实践已经被不少的团队所采纳。从今年年初开始,咱们开始了一个项目新版本的开发,因为项目具备的不肯定性,以及开发周期不是特别紧,咱们团队决定在开发流程和质量控制上尝试着作些改变,在趋势,Change是深植入企业文化的一个特质,这里的Change不仅仅只包括老板和管理团队自上而下的Change,还包括开发团队和个体,只要你有想法,你均可以尝试着去改变。(以前看过一篇《测试驱动开发的半年实战心得》,也来自咱们团队另外一个成员在该项目中对于TDD的新尝试)数据库

  简介编程

  正如Martin Fowler所说,CI要求开发团队可以频繁地集成开发和测试工做,以便尽早发现问题,减小项目风险。这里的关键是“频繁”,若是CI也只能天天在夜里作一次集成,那和原来的daily build又有什么大的差别呢?架构

  CI实际上是由一系列的最佳实践所构成:框架

  ·        源代码的版本控制和管理ssh

  ·        自动化构建工具

  ·        自动化测试oop

  ·        代码审查单元测试

  ·        自动发行和部署

  ·        持续反馈

  ·        等等

  经过持续地对代码和测试进行尽早频繁地集成以尽早发现问题,而为了可以频繁地集成,又对自动化提出了很高的要求,毕竟只有机器自动完成才有可能在一天里集成若干次(若是须要专人来负责这件事情,第一老板不会赞成,成本过高了,其二人老是不免有出错的时候,结果可能集成自己花费的时间超出了开发的时间,这就得不偿失了,其三,因为人的适应性和“包容性”,也会让规范很难造成并遵照)

  实践

  既然CI包含了这么多实践,咱们决定采用渐进的方式来开展,罗马不是一日建成的,在这个项目中,咱们依次展开了:自动构建、持续反馈、自动测试和自动部署等实践,其中没有包含代码审查的部分。因为趋势已经有一套成熟的版本控制和构建系统(采用Perforce进行版本控制),这使得咱们的自动构建变得相对容易,因此咱们以自动构建为基础,展开以下的一些实践:

  - 增量编译(Incremental Build):CI系统会按期监视Perforce(每5分钟),一旦发现有新的代码check in,就会触发增量编译,取出最新check in的代码进行编译,完成后给check in代码的人发出邮件通知(成功或者失败),若是编译失败,对应的owner必须优先解决,不然CI会每隔一段时间(5分钟)再次尝试,一直到成功为止。因为增量编译很快,Developer通常在check in代码几分钟后就能收到通知,若是失败能够马上予以修复。

  - 单元测试(Unit Test):CI系统在增量编译经过的基础上,会经过咱们的测试框架自动调用每一个模块的单元测试,一样也会发出测试报告,若是测试失败也要优先解决。这里因为咱们项目目前尚未太多单元测试的case,所以咱们第一步先把测试框架搭建好,而后对项目中新的代码推行单元测试,而对于legacy代码,则视状况补充case。

  - 自动发行和部署(Full Build & Deployment):CI系统会按期(3小时)执行Full编译和打包,最后生成可安装的发行包,而后经过虚拟机自动部署并安装到远端的虚拟机上。因为完整的编译和打包操做很费时间(半小时以上),所以没有必要对每次check in代码都执行。经过自动发行和部署,CI系统能够尽早发现打包和安装过程当中的问题,并尽早予以解决。

  - 组件测试(Component Test):相对于单元测试,组件测试更关注于各个组件间接口部分的测试,此外,单元测试通常要求没有外部环境的依赖,好比数据库,DNS等,若是必须有这些依赖必须经过mock的方式解决,而组件测试则运行在真实的产品环境里,所以数据库、DNS等外部依赖均可以做为测试的输入输出。这部分和单元测试同样,因为没有现有的基础,所以咱们优先搭建好测试框架,而后对新代码进行测试,对于legacy代码则视状况补充。

  - 自动化功能测试(Feature Test):这是咱们现有作的作多一部分,趋势QA会对不少的功能测试case进行自动化,天然在CI系统中也会把这部分归入。咱们采用天天一次的周期来运行这部分测试。

  - 覆盖率(Coverage):既然在CI里包含了这么多的测试的内容,那如何衡量测试的效果和标准?覆盖率即是一个可行的量化标准。所以咱们在CI中也加入了覆盖率的统计,经过代码覆盖工具,咱们能够获得测试运行的代码行覆盖率和条件覆盖率。这些结果也会被汇总到CI报表里,这样咱们随时看到测试的效果和历史数据的改进。

  - 反馈及可视化:在CI里还有一个很重要的部分就是反馈和可视化。有效的反馈机制可让产品的问题尽早暴露并通知到合适的人。而同时经过CI中的可视化能够展现不少信息,好比测试用例的数量,覆盖率,成功和失败构建的次数,代码check in次数等等。经过可视化,能够达到:一、让团队成员了解项目现状,增长成就感(想一想若是你天天能够随时在报表里看到因为本身的工做而增长的部分,是否是很酷?)二、让manager随时了解团队现状,减小项目风险。


工具

  工欲善其事,必先利其器。这里介绍一下咱们在CI实践中用到的一些工具以及选择的理由。

  CruiseControl,咱们选择它开始CI系统,在选择它以前咱们也考察了其余一些CI系统,最终CC胜出也是有不少理由的:

  - 首先很重要的理由CC是免费开源的系统,咱们在CI上也刚刚开始尝试,不太可能去考虑那些很贵的商业系统

  - 其次,CC提供了不少的SCM工具的集成,好比Perforce,SVN,Starteam等等

  - 此外,CC有很是好的扩展性和定制能力,在CC的build loop里能够添加不一样的Task来增长额外的支持,好比咱们的不少测试task、覆盖率等均可以很方便地加入。

  - 最后,CC有着不少的用户,所以在网上能够找到比较多的支持文档。

  Python,咱们选择python做为咱们不少定制task的编制脚本,同时也使用python做为测试框架的脚本(以python测试框架Nose为基础)

  CppUnit/xUnit,这个不用介绍,单元测试必选的测试框架。

  Bullseye,使用bullseye做为覆盖率工具,它能够统计行覆盖率和条件覆盖率,而且有很好的命令行脚本支持。

  VMWare,组件测试和功能测试都须要自动部署到虚拟机执行,所以咱们选择了简单好用的VIPerl做为VM的控制脚本。用它进行VM snapshot管理任务。

  此外,还用到了不少附属的工具集,好比ssh,expect,ant,XML/XSLT,等等。在构建CI系统中一个体会就是,尽量使用现有的工具,经过粘合胶水(好比python)将它们串起来完成复杂的任务,从头造轮子不多是CI最有效率的选择。

  心得

  最后,谈谈在此次CI实践中感觉到的一些心得:

  CI和process及agile:敏捷编程中要求在每一个小迭代中都有交付件,所以要求每一个迭代都有完整的集成及测试工做,于是CI是一个很好的敏捷实践,用以保证交付件的质量。若是没有很好的CI,很难作到真正的敏捷。此外,CI的引入也会对现有流程造成必定的影响,一个实际的例子就是:之前RD老是在天天晚上下班前把当天完成的代码check in,而如今则是,完成了一部分就当即check in一部分,并等待几分钟,确保check in的代码不会让CI失败。

  CI和testing及automation:其实在前面的实践中也已经看到,CI中包含了不少的测试实践,好比单元测试、组件测试、功能测试、系统测试等等。Integration不仅是Compile,更多地是经过测试来保证质量。这对RD和QA都提出了更高的要求,首先,持续意味着咱们必需要保证测试的一直可用,在实施CI以前,咱们也有单元测试,但单元测试每每在进入alpha或beta后就再也没人关心和维护了,在项目结束时甚至单元测试的程序连编译都不能经过。其次,自动化的要求意味着必需要更好地去考虑产品设计、实现、以及测试的设计工做,一个低耦合的架构才有可能更多地自动化,糟糕的设计工做会让自动化根本没法进行。

  CI和cross-platform开发:趋势不少项目都有多个平台的版本,所以对软件的跨平台开发也有很高的要求。那CI对跨平台有什么意义呢?若是咱们在多个开发平台上都有响应的CI系统,那咱们在开发任何一个平台的时候,新增或者修改的代码均可以及时经过其余平台上的CI系统获得尽早的验证和反馈。这样,经过CI能够更好地要求开发人员考虑跨平台的须要,不能由于一个平台的代码而让其余平台的CI失败。

  “持续”:我想对CI里“持续”的理解能够从两方面来谈,首先是持续地集成产品,尽早地发现问题;其次,也能够把这里的持续理解为持续改进,正如前面说的,CI里包括不少的实践,咱们不可能一会儿引入所有,这就要求咱们有持续改进的sense,持续地引入新的实践(好比加入代码审查等)、持续地加入新的case、持续地完善CI和process,在改进的同时,CI又很好地保证了已有部分的长期有效,不过像猴子摘西瓜那样,缺乏历史的积淀。

  企业文化和公司的支持:最后一点心得,和CI关系不大,但在任何公司、任何组织中,要想能不断改进、尝试新的实践和流程,必然离不开组织和制度的支持。咱们在实践CI过程当中,manager们给了团队不少的自由,能够充分去发掘,同时容许失败,这是任何一个实践可以有所收获的必备前提。

  最后,推荐一本关于持续集成的书籍:Continuous Integration: Improving Software Quality and Reducing Risk(持续集成:软件质量改进和风险下降之道),它对CI进行比较全面的介绍,能够从这本书里开始对CI作个全面的了解。

  CI并非软件开发的银弹,它也并不尝试解决软件开发中固有的不少问题,但经过采用CI,能够更好地控制和下降风险,并能更好地保证团队和流程走在不断成功和改进的正确道路上,从而让咱们有更大的信心去release产品,refractor代码,agile流程。

  拥抱敏捷、拥抱变化、拥抱CI!


【转自:http://www.51testing.com/html/35/n-142135.html】