6.8 案例分析:改进自动化工具

在开发自动化系统RECBIN(垃圾箱)之前,我们的DB3项目版本为v9,小版本v95,Fixpack为FP6,产品每年都将发布3~4个Fixpack,而当年我们同时面临主版本v10的压力,一半左右的开发和测试人员被抽调到新版本的开发上,剩下不到一半的工程师将对老版本的工作遵循维护和修复的策略,因而在v9的FP项目中,回归测试是工作重点。

不久以后,我们被告知测试人员还要减少,但仍需完成同样甚至更多的测试工作。同时,新版本的开发工程师因为曾在v9的工作中承担重要模块的开发工作,虽然要求平缓交接工作,但仍然会负责修复很多遗留下来的质量缺陷并检入到v9的版本中。也许是因为不够重视,在v9上检入的策略带来了大量的回归问题,这给我们的测试团队带来了不少往复的工作量,v9的内部发布版本在很长一段时间内都表现不佳,测试团队压力非常大;而且随之而来的v10的投入逐渐增加,v9上的工作越来越表现出测试在拖后腿,疲惫不堪地在抱怨声中哀怨度日。

我就是在这时加入了这支9个人的测试团队,我们的主要任务是负责v9和v10的冒烟、功能、回归测试,我们需要用两个月的时间对原有测试工作做出改进。

v9和v10的功能测试主要面对的是已经开发的约220个测试用例,部分用例使用C++、C语言编写,部分用例使用Java语言编写,其余大多使用perl语言编写,中间不乏有链接数据、JDK等外部工具包调用,这些脚本和用例都是前辈工程师花了数年时间开发出来的,被认为是可以覆盖整个产品所有功能点(当然会有重复覆盖)的“系统工程”,也就是在脚本的文件、文件夹上做了合理的“分类”,每个脚本都包装成了“Bucket”,每个Bucket中都包含执行文件、结果文件、引用包链接文件等,每个执行文件的编写都很规范,有不少注释信息,新来的测试人员还是比较容易通过阅读每个Bucket的Readme文件以及执行文件的前几行注释上手工作的。不过,因为这些Bucket有的太过庞大,测试文件少说有几千行代码,一个重量级的Bucket光计算机运行就达到20个小时。好在还有在产品线上工作了近20年的老工程师,否则这些测试脚本真会成为我们的重负。

在接手项目时,资深的美国测试工程师与我们分享的不仅仅是这些测试用例的阅读方法,也给我们做了有价值的自动化监测运行时错误的自动化报告功能,这个功能也是迄今我发现的最有“范”的自动化测试,对我启发很大,在以后很多场合我都会自豪地向自动化测试工程师推荐这种方式。我们看看如图6-20所示Bucket的构成。

00045.jpeg

图6-20 Bucket的构成

·测试用例文件:cube.crv和cube.drv。

·执行日志文件:cube.trace。

·测试输出文件:run文件夹下名为cube.rrn的文件,同名的clp文件是入口执行文件即cube.clp。

·标准答案文件:exp文件夹下正确的命名为cube.rxp的文件。

·错误检查文件:错误发生时,run文件夹与exp文件夹下同名的文件对比出的“误差”打印到err文件夹下以.err结尾的同名文件。

·测试结果统计文件:res文件夹下为cube.res的文件。

·可执行文件:test文件夹下许多被调用的测试文件,如图6-21所示。

00006.jpeg

图6-21 Bucket目录Test下文件列表

不同类型文件的内容示例见图6-22~图6-24。

当测试产生错误,即run和rxp文件出现误差时,err会显示出“缺少”、“错误”、“多增加”的输出结果,这是我们定位错误的简单办法。err文件的内容见图6-25,测试结果见图6-26。

00117.jpeg

图6-22 可执行文件clp的内容

00089.jpeg

图6-23 可执行文件run的内容

00096.jpeg

图6-24 可对比的期望值文件exp的内容

00024.jpeg

图6-25 当RUN文件与EXP文件产生差异时生成的ERR文件内容

00039.jpeg

图6-26 测试结果生成

在测试中,可以说封装好的Bucket是一个拥有完整故事的测试用例,而手动执行这类测试需要上百步的操作,包括创建数据库、执行表单动作等,每一步都存在人为错误的风险,即使不出错,因为人为的干预远远比计算机的工作效率低下,测试工程师在这样的自动化环境下可以在450个计算机运算小时后完成一次完备的测试,这包括了100多组测试用例(bucket),以及不同的配置模式:

·122组使用Perl和C++编写的复杂用例

·9个平台(linux,unix,windows,etc)

·8个数据源(DB2,Oracle,Teradata,Sybase etc)

·2个模式(SER,MPP)

·2个隔离模式(DJ_FENCED=YES,NO)

自动化的平台不但可以自动化部署build,也可以从部署的build中自动化地执行回归测试,这个阶段称为API自动化测试阶段,经历半年的工作环境熟悉和技能的成长,测试团队的主力可以并发1~2个环境,发起指令执行自动化测试的清理环境、建立数据、测试、收集结果,而并发度很快成为瓶颈,资源的竞争也是问题。最重要的是,精力的分散使得结果并没有像设想的那样,增加测试机器并没有提高测试效率。我们找到了真实的原因,即bucket的执行依赖环境和配置的敏感度极高,一旦测试的准备和环境的清理工作不够到位,或者遗漏了一个步骤,我们的测试只能推倒重来。就这样,在自身技能和熟练程度的不断提高和并发能力的不断提升下,我们的效率和测试的进度在一定程度上一直保持着一个令人不怎么满意却很疲惫的水准,与此同时,来自管理层的压力和项目进度的压力迫使我们做出更大的调整。

API自动化测试阶段所遇到的最大挑战是:

·如果因为产品出现回归,我们将在两个月以后发现问题。

·我无法知道这两个月间哪个build质量最优。

·测试人员需要反复执行相似但又非相同的参数配置,而测试人员专注于测试配置以至于很难多线程并行,测试效率较低。

·测试人员将很多时间用于测试环境问题的诊断和排除,需要手动清理的频率很高。

·First Catch错误常常很难重现。

于是我们改进了自动化测试方案,特别是环境部署和配置,这部分工作极易出错,我们增加了perl语言写的autodeploy.pl+系统参数(例如linux64+20110301),这样可以跨平台安装和配置。为了在干净环境里运行测试,我们写了cleanmode.pl来删除无用临时文件,恢复数据库空间,将系统环境参数恢复到初始状态;此时,我们已经做到了相当程度的持续化集成+持续化测试。

·因人为失误和环境原因造成的测试错误显著减少,无效defect数量减少,测试的速度有了明显的提高。

·每个测试用例可以减少30分钟的等待和人工干预的时间,一年可以减少1180人时的工作量,相应地,完成一次覆盖的测试时间也减少了(但如果平均到每个版本发布中,这种提升还不够明显)。

那么持续化测试阶段的测试模式是怎样的呢?如图6-27所示,我们将bucket的执行进行了封装,这样可以使用计算机的批处理来批量执行而无需人为干预。为了统一输出和便于发现问题,我们将执行的输出也进行了一定的标准化,DJrun就是这样一个工具。通过这些操作,屏蔽了各种不同的语言完成的bucket在测试时使用不同方式执行的差异性(当然还是有些bug,测试首次执行成功率依然是我们的一大挑战),在终端,测试人员只需要找一个slave测试机,当数据库、测试所需调用的外部其他资源均允许时,即可运行auto.pl。

00011.jpeg

图6-27 AUTO.PL实现自动化加载测试脚本、准备环境和发出执行指令

我们设计了一套验证自动化测试产出比以及有效性的调研方法,包括5个问题,将其分发到每个测试成员手中,请他们如实填写,这5个问题是:

1)如果使用100作为您过去执行日常测试工作所花去的工作量(没有当前测试工具),那么,如果使用当前测试工具完成这个工作,需要花费的工作量是多少(1~100)?

2)有多少工作量花在了维护和开发这样的自动化工具上(1~100)?

3)一个新员工需要花费多少时间掌握自动化测试的技能并独立完成工作(人周)?

4)在最近的一次测试项目中,有多少测试用例已经被自动化了(百分比)?

5)有多少质量缺陷是在自动化测试中被发现的(百分比)?

经过两个小组的参与,我们取每个小组的平均值,得到的结果是,使用持续化测试的自动化测试后,相比原来的API测试增加了约15%~30%的产出,见表6-1。

表6-1 方案1改进效果反馈调查结果

00110.jpeg

这种持续化集成+持续化测试所遇到的挑战是:

·多人并行测试时,经常会出现资源冲突,例如数据源同时被操作造成了死锁,或者是同一台测试机器被两个人同时操作造成崩溃等问题。

·测试机器一旦出了问题,恢复起来所面临的问题比起先前更加复杂和耗时。

·开发环境发布build以后,从美国到中国同步这个build需要近10小时,而不同平台上的版本发布时间也不一致,需要人为kickoff清理环境和安装,从build同步完成到真正开始测试环境的部署,中间的时间浪费也不可小觑。

在进一步改进现有的持续化测试方案后,再次统计团队在使用新方法后的体会,我们使用了同样的5个问题,他们给出的答案如表6-2所示。

表6-2 方案2改进效果反馈调查结果

00034.jpeg

总而言之,不但总体的效率和投入产出比API自动化测试提升了60%,系统利用率、自动化覆盖范围和人力资源的介入频率也得到了明显提升:

·系统利用率提高50%。

·自动化能力和覆盖范围提高50%。

·敏捷性和快速测试能力提高90%。

·系统的大规模测试灵活性提高60%。

·其他资源利用率提高了80%。

·管理和人为介入的消耗减少了70%。

·安全性提高60%。

·资产以及人力资源消耗减少了90%。

这个改进的持续化测试系统是如何设计的呢?我们找准了需要自动化的重点区域,加强了自动化的程度,重新在原有系统的外部设计了自动化BI系统,也优化了内部的测试结果。

在外部使用Build Forge工具和编写的负载均衡Java程序联合起来自动启动build下载安装,分配workload。我们把能找到的所有计算机,高性能的、低性能的,横跨9个平台共20多台计算机变成Slave测试机,而如果某台机器因为故障下线,系统的测试负载均衡功能可以将测试任务平均分配给剩下的可用测试机。

因此,一旦同步build被检测已经生成并复制完整,测试系统将立刻下载并配置测试机。工作完成以后,Build Forge的任务逻辑将做出条件选择,是继续测试或者将当前不佳状态的测试机退出测试计划系统,因此彻底解决了人为交互所造成的资源冲突问题,解决了build同步造成的时间等待以及bad测试环境影响测试进度的问题。可以说真正做到了持续化集成和持续化测试的所有工作。

而在自动化分析错误方面,我们在BI中增加了对典型错误的自动判断,将典型错误所带来的log关键词作为监控对象,一经发现即直接生成可读性的跟踪和质量缺陷报告。同时,Slave测试机往复运行,永不停息,每执行完一个循环均会寻找build同步系统中的最新build,并进行自动下载和配置。

而测试的报告都将上传至服务器,测试报告的状态以测试时间和版本排序,这样很容易判断和排除偶发的无效质量缺陷。

下面给出改进的持续化测试系统的设计架构——RECBIN系统架构(如图6-28所示),希望对各位实现自动化测试框架有所帮助。

00003.jpeg

图6-28 RECBIN系统架构