第2章 终极数据库自动化
Henri van de Scheur
Henri van de Scheur讲述了一个跨越6年的故事,是有关他和他的同事在开发一款适用于多个环境的测试数据库工具时所发生的事情。他们为自己的自动化测试设定了良好的目标,并为测试工具搭建了一个良好的架构。他们使很多测试实现了自动化,从而为自动化测试构建了一个完整的生命周期,包括周期性的bug清理。测试是每晚、每周运行的,或者根据特殊的时间表来安排执行。虽然取得了巨大的成功,但他们也遭遇过一系列的问题,Henri都如实地进行了描述。这个数据库测试工具(现在是开源的)是由一支小团队短短几年内在挪威开发的,并且取得了非常可观的投资回报率(ROI),如表2-1所示。
表2-1 案例研究特征
2.1 本案例研究的背景
这个案例研究描述了我(指Henri)在一个快速成长的新公司里的经历:刚开始的时候,大约有50个员工,但仅仅过了五六个月,员工数量就增加到超过100人。由于人员数量增加太迅速,导致后来加入的很多开发人员和测试人员缺乏对产品的基本了解。知识的交流被极大地忽视了。结果,产品和测试的质量都很差。
办公室里有大约50 ~ 60个开发人员及20个专用测试人员,分别分布在同一办公大楼的各个楼层。测试人员报告产品中存在的问题,但由于测试质量差以及缺乏对产品的充分了解,以致这些问题往往被忽视。通过改善开发人员和测试人员两个群体间的交流,开发和测试工作都从中受益并且质量都得到了提高。所以,良好的交流是开始考虑自动化测试的先决条件。
【真知灼见】
不要尝试对设计很差的测试实施自动化,先完善测试,再进行自动化。
一个包含大约30 ~ 40个测试的典型的发布测试只在一个平台上运行,这就可能需要15 ~ 20个测试人员花费3 ~ 4周的时间。同时,由于发布测试中有更多的bug修复周期和测试周期(一般是4 ~ 6个周期),因此,在可以发布一个产品的新版本之前,过去需要大量的时间。由此可见,将以上过程实现自动化的需求是非常显著的:周期必须缩短,人力资源必须减少,并且测试人员必须在多个平台上运行测试。
一开始,我们使用Java语言开发了一个能够满足以上需求的内部工具,随后再将更多的新功能逐渐添加进去。到目前为止,这个工具的一个更新的版本也已经开发出来了,且又增加了一些新功能。测试也是用Java语言开发的。虽然自动化测试是从GUI自动化开始的,但是基于命令行界面的测试也变得日益重要,因为它可以使团队更方便地通过已安排的分工协作进行自动化。
虽然当时有一些现成的测试套件可用于测试数据库,但是我们并不知道使用什么自动化工具来进行数据库的测试。另外,我们的数据库有当时市场上还没出现的一些特殊功能,而这是现有的测试工具无法测试的。虽然当时已经开发出了一款内部测试工具,但是它根本没法满足我们的需求。那时,我们突然有一些可用资源来开始这样的一个项目,基于这些原因,我们进一步开始测试工具的开发。
2.2 测试中的软件
该项目中要测试的软件是比较特殊的,因为它仅仅只包含数据库。虽然有一些现存的测试套件可用于测试数据库,例如测试多个数据库API和查询语言之间兼容性的测试套件,包括JDK(Java Development Kit)、JDBC、ODBC(Open DataBase Connectivity)和SQL,但是这些工具的使用并不广泛,并且(或者)它们仅仅只是为使用它们的数据库量身定做的。所以本案例研究中的测试和测试工具都是内部开发的。
我们定义了一个操作系统组合而成的平台,包括它的品牌和JDK版本。我们后来又将另一项包含进去:平台是32位还是64位的。
例如,包括以下几项:
Solaris 10 SPARC, JDK 6, 32位;
Solaris 10×64, JDK 6, 64位;
Solaris 10×64, JDK 6, 32位;
Solaris 10×86, JDK 6, 32位;
Solaris 10×86, JDK 5, 32位;
Windows Vista 64, JDK 6, 64位。
2.3 自动化测试的目标
在《Software Test Automation》(Addison-Wesley,1999)一书中,第8章有一张非常有用的表,列出了自动化测试的不同目标。当我们开始自动化测试时,根据这张表,按照优先级顺序,列出下列这些测试目标:
增强在软件质量方面的信心;
更早进入市场;
减少测试开销;
保持可重复性测试的一致性;
自动运行测试;
找出回归测试中的bug;
经常运行测试。
第一阶段实施完成之后,又加入了以下测试目标:
质量更好的软件;
测试更多的软件;
性能测量;
找出更多的bug;
在不同的操作系统上测试。
【真知灼见】
刚开始不要设定太多目标,最初先重点完成某些目标,再逐步添加新的目标。
另外,在更深入的自动化的全新迭代周期中,我们又制订了新的目标:
1)收集统计数据来制定度量标准(用以回答以下问题):
① 在哪个操作系统上找到的bug数量最多?
② 在同一个操作系统上将测试进行分割会不会漏掉一些bug?
③ 哪些bug是在特定操作系统上才出现的?是在哪种操作系统上出现?
④ 哪些测试发现的故障数量最多?
⑤ 哪些测试从来都没有发现故障?
⑥ 哪些失效是由发布测试发现的,而不是由每晚的测试所发现的?这有利于我们分析为什么这类故障在发布过程中比较晚时才发现。
2)将未使用的硬件用来做其他的事情。
3)尽量达到每周7天、每天24小时不间断使用硬件。
4)缩短bug从发现到反馈给相关人员的时间间隔(最初从几周缩短到几天,然后缩短到只隔一夜,最后缩短到检查代码之后就直接完成反馈。)
5)使用我们自己的数据库来收集统计数据,这样就可以在真实的产品环境中拥有自己的数据,并且有可能会遇到在其他没有发现的故障(用你自己的方法来解决)。
6)使测试场景不可能手动运行。
7)使场景维持几天。
8)使场景具有多个用户。
9)重新使用预处理任务,并使其自动化。
10)重新使用后续处理任务,并使其自动化。
11)对于测试结果自动生成测试报告。
12)完全的自动化测试。
2.4 开发内部测试工具
该内部测试工具的基本功能是由3 ~ 4位开发人员在6 ~ 9个月的时间内开发出来的,是用Java语言编写的。第一个版本开发之后,一个人专门负责对其进行维护和进一步的开发,显然维护和进一步开发的工作量是逐步减少的。
图2-1是测试的Java引擎(Java Engine for Testing, JET)架构的一个概览。每个大的矩形都是一台运行某些软件的计算机。
我们在图2-1中的运行机(runner)处开始运行一组测试集合。它使用JETBatch来开始运行测试并收集运行结果。客户端(client)运行与JETBatch进行交互的Jet代理程序(JET Agent,JAG),即使用JAG来启动JET运行单个测试。这些JET读入一个XML文档,该文档会给JET提供测试运行的内容,并与服务器的JAG进行交互来启动我们需要测试的软件。整套系统还包括一个测试装置,通过使用不同的机器操作不同的任务,避免了架构本身的资源消耗对被测任务的影响。
因为我们确实投入了大量的时间和精力来设计自动化测试,所以几乎实现了所有的目标(只有性能测试是由我们的另一款内部开发工具完成的,这不在本案例研究的讨论范畴)。几乎所有的测试都是通过我们的工具自动运行的,其中只有几个测试,我们认为自动化的价值并不是很大,是由手动完成的。最后,我们有了一款可以在很多不同领域使用的、功能非常强大的工具。
图2-1 测试工具的架构
2.4.1 配置
测试配置:我们的测试是定义在一个数据库中的,并且可以单选、成组选择或者根据特定序列来进行选择。工具在每次测试之前都会进行一次初始化,避免前面的测试结果影响到后续的测试,工具在每次测试之后也会将测试环境清理干净。工具还自动将测试件进行收集和归档。
【小窍门】
把实施预处理和后续处理作为启动一个测试套件的一部分。
测试时应用程序的配置:可以对产品版本进行选择,包括调试版本和来自开发人员“沙箱”(sandbox)的本地版本。
服务器和客户端平台的配置:我们使平台的定义和在运行测试的平台组的定义变得简单。根据测试装置在一个平台组(例如,Windows Vista,64位,JDK 6)里面是否可用而将其划分成不同的测试装置。我们可以用一到两个平台为服务器设置一个单独的配置,通常也可以用一个平台为客户端设置一个单独的配置。对于客户端和服务器来说,都可以选择不同的操作系统。
一个标准的测试需要4台机器:一台测试机器,一台客户机,两台包含被测数据库的服务器。
2.4.2 资源优化
通过添加更多的机器到测试装置池中,我们可以并行地运行测试。另外,测试具有排队机制:一个测试装置上的测试完成之后,候选队列里面的下一个测试就开始运行。
2.4.3 测试报告
这个内部工具创建了网站来记录测试报告,所有的结果在一个数据库中也进行了详细存档,这有利于我们建立详细的度量,比如下面的度量:
1)在哪些平台上会有一些什么样的bug及其出现的频率(可以帮助指定bug的优先级)。
2)每个平台上的一般信息统计。
3)测试中bug的检出率。
4)测试的冗余。
一个测试完成之后,会自动发送一个包含测试结果的汇总邮件,同时生成一个XML文件,它包含了用以导入到其他数据库或者报表生成器的所有必要信息。
该工具也使得从开源测试覆盖工具(EMMA)中导入信息变得更容易,而且让我们能观察到测试的质量——至少从表面上看是这样的。
2.4.4 故障分析
在测试失效分析达到60% ~ 80%正确率之后,才能对失效进行自动识别。比如,通过定义描述故障的模式和标记来进行识别,在大多数情况下,我们定义一些模式或者签名对故障进行描述,这些模式或者签名通常与测试产生的错误信息、测试名称和产生这条实效信息的测试语句直接相关。一个bug可能有多个标记,如果要对新的故障或者已知故障的新症状进一步进行人工分析,就需要新的标记信息。
用这个新工具实施的某产品的首次发布测试中,要求不论何种原因,无论是产品原因或者是测试原因,至少75%的测试运行的时候不会出现故障。最后,要求至少96%的测试运行的时候不会出现故障。
2.5 结果
该工具经过3年的开发和使用,在6 ~ 10个平台上有200个测试的发布测试,可以仅由一个人在3 ~ 4天内运行完成。这等价于(在实施自动化之前)在16天的时间里(16:4)20个人(20:1)在一个平台上(6:1)运行了40个测试(200:40)。所以自动化测试过程帮助我们提高了至少2400倍的工作效率!
【真知灼见】
用一种最恰当的方式向希望知道结果的人们来表述你的成功(这里的表述是,“将效率提高了2400倍”)。
现在所有的测试人员都可以集中精力进行测试的开发和进一步的工具开发,跟刚开始需要进行重复性的工作相比,他们现在的工作也不会那么枯燥了。我们的产品和测试的质量都得到了极大的提高。开发人员和测试人员都得到了应有的相互尊重,并且他们互相通过挑战来激励自己,这样使他们工作的兴趣更浓。
通过实施自动化,维护工作只占测试人员整个工作量的不到1/10,而且比之前的工作量要低很多,部分原因是因为产品进一步开发中的其中一个需求是后向兼容的。这是一个罕见的机会,测试与测试工具本身因为新的功能而需要改变。另一方面,新的功能通常需要新的测试,在某些情形下用以替代旧的测试。
(未完待续...)
最新内容请见作者的GitHub页:http://qaseven.github.io/