标签 持续集成 下的文章

持续集成术语解释

Continuous Integration(持续集成):持续集成要求开发人员频繁地提交他们的所完成的工作产品,这个频率通常是至少每天一次,有时候可以多次。每次集成会通过自动化构建(automated build)的方式进行尽量快速地验证,以确保新提交的变化不会造成新的问题。如果在集成的过程中出现异常,则应当快速的反馈给相关的人员。
Build(构建):构建是将源代码放在一起,并验证软件可以作为一个一致的单元运行的过程;验证活动一般包括编译、测试、审查和部署。
Build Tool(构建工具):用于执行构建过程的工具称为构建工具,它通过执行构建脚本实现自动化的编译、测试、审查和部署。Make是所有构建工具之祖,它向我们展示了依赖关系检查和增量式构建,Make可以通过选项用于构建任何语言编写的软件;其他常见的构建工具往往和语言相关,例如Ant:Java、NAnt:.NET、Maven:java、Rake:Rake。
Daily Build / Nightly Build/Weekly Build:每天/每晚/每周 做一次构建。
Daily Run(每日执行):每天都对系统的某一个或几个版本运行自动化的测试。
Build Verification Testing:验证Build是否成功,它是进行后续测试工作的前提。 随着软件功能越来越完整和稳定,BVT会逐步加入一些成熟的自动化测试脚本。
Single BranchTrunkMainline:对于一个产品的源代码测试代码配置数据,在配置库中以单一主干(truck)的方式统一管理。
Release Branch(发布分支):当开发主干中含有某个发布版本所计划的特性时,便可以从主干中拉出一个发布分支用于支持该特定发布版本。一般来说,在发布分支中主要是进行bug修复以及版本发布元数据(例如版本号,构建日期等等)的准备工作,不允许增加新的功能代码。
Hotfix branch(热补丁分支):当已发布或上线的版本出现重大bug需要立即解决的时候,便可以从对应版本的标签创建出一个热补丁分支。热补丁分支和发布分支十分类似,它的目的也是发布一个新的产品版本,尽管是不在计划中的版本发布。使用热补丁分支的主要作用是让在热补丁分支上进行快速的产品bug修复的同时,尽可能减少对其他开发人员的影响。
Feature branch(特性分支)/topic branch(主题分支):特性分支(有时也被称作topic分支)是用于开发某一个特性集而从主干中拉出的分支; 特性分支的重点是,只要特性还在开发,该分支就会一直存在,不过它最终会被合并回主干(将该特性加入到某个计划发布版本中),或者被丢弃(如果试验的结果令人失望)。
Local Build(本地构建):将变更提交到版本控制库之前,在RD开发机上执行的本地构建,目的是尽可能避免因为check in动作而导致主干被破坏。
Build Pipeline (构建管道)/staged build(分阶段构建):构建管道,即多个构建按一定顺序执行。一般先运行轻量级的构建,再运行更大范围、耗时更长的构建,通常是指那些较慢的功能/集成/系统测试。
Version Control System(版本控制系统):提供一个受控的访问库来管理源代码和其他软件资产(如文档)的变更,让开发者以及项目相关人员能够有效管理软件版本。版本控制系统能够让您按时间回溯,取得源代码和其他文件的不同版本。常用的版本控制软件有SVN,CVS,GIT等。
Continuous Integration Server(持续集成服务器):CI Server自动完成软件代码的构建过程。CI服务器可以根据设定的触发机制(代码变更、定时等)自动地去完成构建过程。目前已知的各种CI Server不下几十种,其中比较常见有Hudson、CruiseControl、TeamCity、Pulse、Anthill, Bamboo等。

迈出单元测试的第一步

单元测试不仅是软件行业的最佳实践,在敏捷方法的推动下,它也成为了可持续软件生产的支柱。根据最新的年度敏捷调查,70%的参与者会对他们的代码进行单元测试。
单元测试和其他敏捷实践密切相关,所以开始编写测试是组织向敏捷转型的踏脚石。道路漫长,但值得去做。我将在本文介绍符合要求的小技巧,以及在开发周期里进行单元测试的步骤。
有效的单元测试默认要能自动化。没有自动化,生产力就会下降。没有自动化,单元测试的习惯也不会持续太久。依靠手工测试(由测试人员或开发人员完成)并不能持续太长时间;在有压力的情况下,没人会记得去运行所有的测试,或者去覆盖所有的场景。自动化是我们的朋友,所有的单元测试框架都支持自动化,而且集成了其他自动化系统。
单元测试对现代开发来说至关重要
有代码相关的测试,我们就有一个天然的安全保障。我们修改的代码要是带来了什么问题,测试会告诉我们。这个安全保障越健全,我们对代码正常运行的信心就越大,对按需修改代码的能力也就越有信心。
和其他类型的测试相比,单元测试的主要优点是反馈迅速。在几秒钟内运行数百个成套的测试,这对开发流程很有帮助。我们会形成“添加一些代码,添加测试,测试运行通过,前进”的节奏。小步前进、确保一切正常也意味着调试时间会大大减少。测试能提高生产力也就不足为奇了——在Bug上少花时间,把更多的时间用到新功能的推出上。
依赖关系的壁垒
给新建项目添加测试相当容易——毕竟代码不会阻碍测试。不过这种情况绝对不常见。大多数人都是在处理遗留代码,这些代码不太容易测试,有时候甚至运行不起来——它需要的数据或配置可能只存在于生产服务器上。我们或许要为不同的场景创建不同的设置,这也许会花费过多的精力。在很多情况下,我们可能还会为了测试修改代码。这让人无法理解:我们编写测试就是为了能有修改代码的信心,还没有测试又该如何去稳妥地修改代码呢?
代码可测性是语言和工具的功能。大家认为Ruby等动态语言是可测的。对于测试的内部代码,我们可以改变其依赖关系的行为,而不用修改生产代码。C#或Java等静态类型语言则不太容易去测试。
下面有个例子:一个C#的过期检查方法,检查是否超过了特定日期:
public class ExpirationChecker
{
private readonly DateTime expirationDate = new DateTime(2012, 1, 1);
public bool IsExpired()
{
if (DateTime.Now > expirationDate)
{
return true;
}
return false;
}
}

在这个例子里,IsExpired方法的DateTime属性对测试运行时间有强依赖。Now返回的是实际时间。这个方法有两种情况,它会根据日期返回不同的值。修改计算机时间是绝对不行的,因为我们要在任何时候到任何计算机上去测试场景,并且不能带来任何副作用。
要测试到两种情况,一种可能的解决方案是修改代码。比如说,我们可以把代码修改成:
public bool IsExpired(DateTime now)
{
if (now > expirationDate)
{
return true;
}
return false;
}

这样,测试可以注入不同、可控的DateTime值,而不用在生产代码里写定一个值。我们要是不能修改代码,可以利用Typemock Isolator等Mocking框架,模拟静态属性和方法。针对先前的代码,测试可以写成:
[TestMethod]
public void IsExpired_BeforeExpirationDate_ReturnFalse()
{
Isolate.WhenCalled(() => DateTime.Now)
.WillReturn(new DateTime(2000, 1, 1));
ExpirationChecker checker = new ExpirationChecker();
var result = checker.IsExpired();
Assert.IsFalse(result);
}

现有的遗留代码不能轻易修改,因为我们没有针对它的测试。开始测试遗留代码之后,我们就能明白:代码越丑陋,测试越困难。工具可以减轻一些痛苦,但我们要努力去构建安全的环境。
依赖关系并不是唯一的内容……
我们很快会遇到的另一个问题是测试维护:测试和被测试代码耦合在一起。有耦合关系,修改生产代码就有可能破坏测试。要是代码修改引起测试失败,我们就需要回去解决这些问题。很多开发人员害怕维护两个代码库,这种恐惧甚至会让他们干脆不进行单元测试。真正的维护工作既取决于工具,也取决于技巧。
编写好的测试是通过实践获得的技能。编写的测试越多,我们就越精于此,同时会提升测试质量,维护也越来越少。有了测试,我们就有机会重构代码,这反过来又会让测试更简洁、更易读、更健壮。
工具对实践的难易程度有极大的影响。在基础层,我们需要一个测试框架和一个Mocking框架。在.Net领域,两种框架的选择都很丰富。
编写第一个测试的准则
开始的时候,我们通常会试用不同的工具,来理解他们的工作原理。我们往往不会在实际的工作代码上开始编写测试。但很快就要给代码编写真正的测试。有一些小提示届时会有用:
•从哪里开始:一般来说,我们编写测试是针对工作代码的,无论代码是Bug修复还是新功能。对Bug修复来说,编写的测试要检查修复。对功能来说,测试应检查正确的行为。
•支架:以我们掌握的知识来看,明智的做法是先添加能确保当前实现运行的测试。添加新的代码之前先写测试,因为我们希望在修改现有代码之前,能有安全的保障。这些测试被称为“特征测试”,这个术语来自Michael Feathers编写的《修改代码的艺术》。
•命名:测试最重要的属性是它的名字。我们一般不会去看运行通过的测试。但当它失败时,我们看的就是它的名字。所以挑一个好名字,描述出场景和代码的预期结果。好名字还有助于我们定位测试里的Bug。
•评审:为了增加测试成功通过的机会,编写第一个测试时我们应该和同事结对。两个人都能从实践中学习,而且我们还能立即评审测试。最好对所测的内容、测试的名称达成共识,因为这会成为团队其他人员的基本模板。
•AAA:现代测试的结构符合AAA模式——Arrange(测试设置)、Act(调用测试里的代码)、Assert(测试通过的标准)。如果我们使用测试驱动开发(TDD),我们要先编写完整的测试,然后再添加代码。对遗留代码来说,我们可能需要换一种方式。一旦我们有一个场景和名称需要测试,那先编写Act和Assert部分。我们要不停构建Arrange部分,因为对需要准备或仿造的依赖关系,我们知道的要更多一些。然后继续这么做,直到有一个测试能够通过。
•重构:一旦准备好了测试,我们就可以重构代码了。重构和测试都是后天获得的技能。我们不仅要重构被测试代码,也要重构测试本身。但DRY(不要重复自己)原则不适用于测试。测试失败时,我们希望尽快修复问题,所有的测试代码最好在一个地方,而不是分散在不同的文件里。
•可读性:测试应该是可读的,最好是人类可读。和搭档评审测试代码,看他能否理解测试的目的。评审其他测试,看看它们的名称和内容怎样与相邻的测试区分开来。一旦测试失败,就需要修复它们,最好还是在运行失败之前评审它们。
•组织:一旦我们有了更多的测试,组织就有了用武之地。测试可以在很多方面有所不同,但最明显的一个就是如何快速运行。有些测试可能在毫秒内运行完,而有些则需要数秒或好几分钟。和工作一样,我们都希望得到最快的反馈。这就是前面谈到的怎么按一定的节奏去进行。要做到这一点,你应该把测试划分一下,把快的测试和慢的测试分开运行。这能手工(努力)去做,但在.NET领域,Typemock Isolator有一个运行器,能自动按运行速度分离。
总结
迈出单元测试的第一步是很有挑战的。体验依赖的东西很多——语言、工具、现有代码、依赖关系和技能。只要稍稍思考,进行大量训练和实践,你就能渐入测试的佳境。
http://www.infoq.com/cn/articles/First-Steps-Unit-Testing?utm_source=infoq&utm_medium=related_content_link&utm_campaign=relatedContent_articles_clk

持续集成原则

持续集成原则
  1. 所有的开发人员需要在本地机器上做本地构建,然后再提交的版本控制库中,从而确保他们的变更不会导致持续集成失败。
  2. 开发人员每天至少向版本控制库中提交一次代码。 
  3. 开发人员每天至少需要从版本控制库中更新一次代码到本地机器。 
  4. 需要有专门的集成服务器来执行集成构建,每天要执行多次构建。 
  5. 每次构建都要100%通过。 
  6. 每次构建都可以生成可发布的产品。 
  7. 修复失败的构建是优先级最高的事情。

持续集成要素

  1.统一的代码库
  2.自动构建 
  3.自动测试 
  4.每个人每天都要向代码库主干提交代码 
  5.每次代码递交后都会在持续集成服务器上触发一次构建 
  6.保证快速构建 
  7.模拟生产环境的自动测试 
  8.每个人都可以很容易的获取最新可执行的应用程序 
  9.每个人都清楚正在发生的状况 
  10.自动化的部署

持续集成的定义

  集成软件的过程不是新问题,如果项目开发的规模比较小,比如一个人的项目,如果它对外部系统的依赖很小,那么软件集成不是问题,但是随着软件项目复杂度的增加(即使增加一个人),就会对集成和确保软件组件能够在一起工作提出了更多的要求-要早集成,常集成。早集成,频繁的集成帮助项目在早期发现项目风险和质量问题,如果到后期才发现这些问题,解决问题代价很大,很有可能导致项目延期或者项目失败。
持续集成的定义
  大师Martin Fowler对持续集成是这样定义的:持续集成是一种软件开发实践,即团队开发成员经常集成它们的工作,通常每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽快地发现集成错误。许多团队发现这个过程可以大大减少集成的问题,让团队能够更快的开发内聚的软件。
持续集成价值
1.减少风险
  一天中进行多次的集成,并做了相应的测试,这样有利于检查缺陷,了解软件的健康状况,减少假定。
2.减少重复过程
  减少重复的过程可以节省时间、费用和工作量。说起来简单,做起来难。这些浪费时间的重复劳动可能在我们的项目活动的任何一个环节发生,包括代码编译、数据库集成、测试、审查、部署及反馈。通过自动化的持续集成可以将这些重复的动作都变成自动化的,无需太多人工干预,让人们的时间更多的投入到动脑筋的、更高价值的事情上。
3.任何时间、任何地点生成可部署的软件
  持续集成可以让您在任何时间发布可以部署的软件。从外界来看,这是持续集成最明显的好处,我们可以对改进软件品质和减少风险说起来滔滔不绝,但对于客户来说,可以部署的软件产品是最实际的资产。利用持续集成,您可以经常对源代码进行一些小改动,并将这些改动和其他的代码进行集成。如果出现问题,项目成员马上就会被通知到,问题会第一时间被修复。不采用持续集成的情况下,这些问题有可能到交付前的集成测试的时候才发现,有可能会导致延迟发布产品,而在急于修复这些缺陷的时候又有可能引入新的缺陷,最终可能导致项目失败。
4.增强项目的可见性
  持续集成让我们能够注意到趋势并进行有效的决策。如果没有真实或最新的数据提供支持,项目就会遇到麻烦,每个人都会提出他最好的猜测。通常,项目成员通过手工收集这些信息,增加了负担,也很耗时。持续集成可以带来两点积极效果: 
  (1)有效决策:持续集成系统为项目构建状态和品质指标提供了及时的信息,有些持续集成系统可以报告功能完成度和缺陷率。 
  (2)注意到趋势:由于经常集成,我们可以看到一些趋势,如构建成功或失败、总体品质以及其它的项目信息。
5.建立团队对开发产品的信心
  持续集成可以建立开发团队对开发产品的信心,因为他们清楚的知道每一次构建的结果,他们知道他们对软件的改动造成了哪些影响,结果怎么样。

Jenkins介绍

  Jenkins,之前叫做Hudson,是基于Java开发的一种持续集成工具,用于监控秩序重复的工作,包括:
  1、持续的软件版本发布/测试项目。
  2、监控外部调用执行的工作。