您当前位置:闸机 >> 帮助中心 >> 浏览文章      |关键词: 质量管理 版本管理 顺极科技

软件开发过程中的质量保证(3)

    日常测试——坚持每日构建

    传统的软件工程中,测试发生在连调之后。这么做的理论依据是,测试依赖于一份一致的、至少能够正常编译并启动的代码。而这个条件在连调之前是无法满足的。

    然而在有了版本控制系统(如, cvs)之后,连调变成了开发中的日常行为。代码几乎在每一时刻都处于高度的一致状态,甚至在许多时候,代码会处于可用状态,从而为测试创造非常有利的条件。

    许多大型开发团队会使用一台甚至多台被称作TinderBox的机器来完成每日构建和测试。简单的每日构建流程如下:

    测试工程师,或代码复审员从代码库中提取一份代码的快照

    相关人员在TinderBox上进行编译

    编译的任何错误被追踪,测试工程师或代码复审员将回退代码到上一次能够成功编译的点,并与此后进行代码提交的其他开发者进行联系,解决问题

    测试工程师对于代码进行测试

    其中,第一、二步是可以通过脚本定时、自动完成的,不需要人工干预。第三步中的编译错误在软件开发中偶尔会发生(这可能来自于冲突合并时引发的问题,但由于开发人员的本地测试,这种文体不会是经常性的),习惯上,这些错误会由代码复审员去追踪和处理,并交给相关的开发人员解决。

    测试工程师可以将编译好的版本交付给一个测试组,甚至用户去进行测试。测试工程师可能随时发布软件的“快照”版本。

    实际上在许多大公司中,每日构建是非常“家常便饭”的事情。我们看到的Internet Explorer版本,如6.0.2600或者类似6.0 Build 2600中的2600的意思就是这份代码之前已经经历了2600次每日构建操作(当然,中间肯定进行过不少修改,而且,也不排除这个2600是故意凑整得到的,但总之,他们进行了相当多的日常构建工作)。

    在软件开发的后期,由于发布的迫在眉睫,每日构建很可能会演化为持续构建,即,每次commit触发一次构建操作。所有问题立即得到反馈。

    为了支持每日构建或持续构建,比较理想的方法是采用Makefile完成构建操作。对于Unix系统,make工具通常是pmake(BSD Make)或gmake(GNU Make);对于Visual C++,则是nmake。大的开发团体通常使用一组脚本来完成所有的make操作,而对于中小型项目,手工地使用类似VC++这样的IDE本身的构建功能也是可以接受的。

    基本的每日构建规范如下:

    基本的每日构建和测试注意事项

    避免在存在开发人员大规模地进行commit时提取快照。此时提取的中间结果很可能有问题,并导致每日构建从头做起。通常,测试工程师和代码复审员在多数开发人员下班的时候开始每日构建,因此,每日构建有时也被称作每晚构建(Nightly Build)。

    标记(tag)每日构建中能够正确编译的版本。这将减少第二天每日构建中的麻烦。

    及时通知造成问题的开发人员,即,所涉及代码的提交者。某些公司甚至要求员工开着手机和寻呼机,以保证工期。

    作为commit mail的有效补充,许多项目开发组会建立邮件列表来传递一些相关的信息。测试日报通常会发给整个开发团队的参加人员,此外,保留一个出现过的问题记录,对于测试环节也会有相当大的好处——这些问题在随后被反复测试,以保证最终的RELEASE不出现这些问题。

    每日构建并不是可有可无的工作,作为日常测试的重要手段,每日构建能够有效地帮助管理者了解工程进度,帮助开发者尽早发现问题,同时,也会促进开发组中的交流。

    有效的版本控制——版本标记、代码分支

    三个文件的“最新版本”分别是1.5, 1.3, 1.4,但最新版本不一定是我们需要的。在这种情况下,版本控制系统提供了一个非常重要的机制——版本标记。例如,我们目前已经确认三个文件的1.4, 1.3, 1.4组合在一起能够正常运行,于是我们在三个文件的这些版本上标注标记TAG_1,如下图:  

协作开发中的质量保证技术
图4. TAG_1标记被打到三个文件的不同版本上

    需要说明的是,标记是可以被移动的。这意味着一旦发现标记打错了,可以把标记移动到别的位置。但在实践中,标记往往同另一个非常重要的版本控制机制——代码分支一起使用。在详细讨论标记(tag)的重要意义之前,我们先来看看代码分支时什么:

协作开发中的质量保证技术

    图5. 比较复杂的情形,一个正在开发的项目中的某个文件,已经完成了2.0和2.1的发布; 其中,BP是指划分分支的切分点(Branchpoint)

    所谓代码分支是版本控制中的一个非常关键的概念。当开发到某个阶段的时候,可以交付一个版本,而主要的开发者则把精力投入到最新版本的开发中。第一个交付分支(2.0)中的一些问题,以及引入的新功能随后在RELENG_2分支中被修正,公司决定发布2.1版本;此后,2.x中的问题继续在RELENG_2中被修正,而一些安全更新,则被合并到2.1-RELEASE中(RELENG_2_1)。

    图5展示的是一个文件上的版本分支。实际的软件工程项目的源代码会由大量文件组成,尽管在本质上分支是针对每一个文件说的,但在被标注了同一分支名称的文件,就像版本标记一样,能够表达一组特定版本文件的集合。

    cvs的版本分支功能有一个很大的缺陷,即,大量文件的切分点(Branchpoint, 即某一个分支最初的版本号)在cvs中很难被指定(cvs支持按某一分支、某一特定时间、某一特定版本来提取文件,但通常不同的文件的版本号并不统一,特别是在大型项目中,肯定有某些文件因为被提交的次数很多,而版本号很“高”的情况)。为了消除这个缺陷,在实践上,我们采用版本标记与分支结合的方法,即,在划分新的分支之后,在这一分支的这些文件的版本上增加一个版本标记。

    例如:对于软件的2.0版,在划分时,将切分出RELENG_2(2.x),RELENG_2_0(2.0)两个分支,而这时的文件的版本,同时被打上一个RELENG_2_0_0_BP的标记。这样一来,在以后比较版本时,我们可以使用RELENG_2_0_0_BP来指定这个版本。当不同的分支又增加了许多修改之后,这个标记将极大地减轻代码复审员的工作量。

    注意,代码分支并不仅限于版本上的用法。事实上,基于同一代码基础的多个不同的软件也可以采用代码分支的方法进行开发。而最终,这些代码还可以合并为一个。

    您可能已经注意到最左边的一组版本序列:1.1, 1.2, 1.3, 1.4, 1.5. 1.6。在cvs中,这一序列被称为“主分支(MAIN Branch)”。尽管并非必须,但习惯上,主分支通常是活跃的开发分支。在这个分支中,人们不断地引入最新的特性,当然,不可避免地,这也可能引发一些问题,而这些引入主分支的问题在随后将被追踪、修订。经过一段时间之后,被“沉淀”下来的代码可以进入另一个叫做“稳定分支”的代码系。

    这样的开发模式通常被称作“多头并进”模式,这样的模式在许多开放源代码的软件开发中非常常见,例如,Linux的单、双号版本、FreeBSD的-STABLE和-CURRENT[2],等等。在一般的商业软件开发中,这种模式也相当常见,特别是在大公司的开发中。拥有多头并进这一能力对于大型软件的开发尤为重要,因为大型软件很可能包含相当多的模块,通过版本控制,问题能够很容易地被整个开发团队追踪。

    多头并进的开发环境中,开发人员可以在粗略熟悉了某个分支的代码体系的情况下参与开发或维护,这意味着,即使某个代码分支的维护人员突然离去,其他人也不用担心通盘阅读不同分支的代码可能造成的理解困难,换言之,对于新的维护人员的要求被降低,从而,软件的开发和维护过程能够更为有序地进行。

相关栏目: