自动化测试或许是一把双刃剑。
今天聊聊大规模自动化测试的话题,对于大厂而言,单个应用就有成千上万的自动化用例(至少我当前所在团队而言是这样),那么每次执行一次测试计划大概1小时。测试用例的难点其实并不在于写用例,而在于测试的维护,测试时间的投入也符合2/8原则。
对很多测试人员来说,自动化测试只是由一些手动生成的、用来执行特定测试场景或一部分产品功能的测试代码组成。
大部分测试人员对于自动化测试可以节省时间这样的说法很熟悉。然而,在很多情况下,自动化测试实际上并没有节省测试人员和他们的管理团队所期望的时间。在现实中,许多自动化的尝试之所以会失败,是因为除了实际的执行程序以外,流程中的其他部分没有一个实现了自动化。为了成功实施自动化,特别是对于大规模的自动化测试,整个过程从头到尾——从测试人员编写完测试程序到结果被分析出来给人看,都必须被自动化。没有这个层次上的自动化,测试人员在监控测试程序运行上所花的时间将会变成难以控制的增长。
对于一个有能力处理上千项测试和分布在上百台机器中的系统来说,系统必须在每一步都必须被完全自动化。对自动化测试的手动支持可能占去测试团队相当多的时间。
测试自动化系统基础
一个最基本的漂亮的自动化系统就可以提高端对端的效率了,更何况自动化系统有着各种不同的形式、规模和闪光点。对所有使用自动化测试的测试团队来说,有一些基本的步骤是共通的。下图显示了一个基本的自动化测试工作流。
在测试开始或接近开始的一些地方,一个测试人员会写一项或多项自动化测试。测试人员也可能会创建测试集。他们可能写脚本,如JavaScript,或者创建一个编译出来的用某一语言写的二进制文件,如C#或C++。在流程的某个地方,这些测试必将运行并且由一个进程来跟踪测试结果(例如,“通过”或“失败”)。一旦有了测试结果,测试人员把新发现的错误输入bug跟踪系统,并且也许会把已经修复的bug相互引用以保证相关的测试现在能正确地通过。
这个基本流程的问题是,在相当多的场景下,人为的干预可能是必需的。一旦测试人员写好测试程序,职责可能是把脚本或可执行文件复制到一个网络共享目录中,以便其他测试人员可以访问到这些文件。在其他情况下,他可能要负责自己去运行测试程序,分析结果和报告。通常,这个测试人员也要负责录入与失败的测试相关的bug,并验证那些被解决的bug是否真正被修复了。
端对端的自动化过程当然可以更加吸引眼球。让我们来看一下一个更加精致的自动化系统和过程是什么样子的。
一旦测试人员完成了编写测试代码或脚本,他们就会把它们提交到一个源代码控制管理系统(SCM)中去,让它的自动构建流程来构建测试程序。一旦构建流程完成,系统会把测试程序和支持文件复制到一个测试人员(包括组成自动化系统的工具)都可以访问的公共位置。用于运行测试的系统的配置是自动发生的。这些机器的部署和后续的执行是自动进行的。一个公共的数据库存放所有的测试结果以方便报告和分析。最后,系统自动地在bug数据库中记录失败的测试。
设计思路
成功的第一步是简单的:测试代码是底盘,需要注重代码质量。
测试代码必须要能够易于维护。无论测试将要运行10天还是10年,在一个大的团队中,很有可能除了作者以外还同时有其他人需要阅读、调试或修改代码。在我观察到的许多团队里,一旦一个自动化测试完成编写并集成到系统,这个测试将永远地留在系统里。
对测试代码的审阅和静态分析也是重要的。对测试服务器路径或者用户名密码硬编码,通常是造成脆弱的测试的原因;而硬编码的资源字符串在非英语版本上第一次运行也是如此。在编译时间或极其接近编译时间分析源代码的工具或脚本对于发现许多诸如此类的常见编程错误是很要紧的。
最后,很关键的一点是,要对测试代码进行源代码控制,并且集中编译和创建。源代码控制通过使测试人员能够研究到测试代码、上层基础结构和附属文件(测试用到的非代码文件,如媒体文件和输入数据)完整的改变历史记录而让维护变得简单。测试代码和产品代码一样会受到频繁的构建和持续的集成。
测试辅助
另一个很多测试团队犯的错误是:他们没能很好地管理测试辅助文件。这里的“辅助”,我指的是数据文件、文档、插件或测试用到的其他数据。保证这些文件有源代码控制是重要的,但是更重要的是要确保这些文件被放在一个满足以下两个关键条件的地方。
第一,文件必须是能够被自动化测试系统得到的。例如,如果网络上设有不同的访问权限,在一个测试团队成员都能访问到的共享目录下的文件并不一定能被自动化系统获取。第二,辅助文件需要放在一个非临时的地方。支持工程和维护团队痛恨接手那些需要从已经不存在的服务器或共享文件夹复制辅助文件的测试。
应对这一问题的补救措施可以包括为测试辅助文件建立一个永久的服务器或使用一个数据库来存储所有的辅助项目。即使不使用这个方案,有一份移交测试辅助的计划书对于保证整个自动化系统的“坚固耐用”也是很重要的。
测试用例管理
随着测试用例的数目由上百到上千,测试用例的管理变成了整个系统的一个关键元素。为了跟踪每项测试在做什么和哪项测试通过了而哪项没有,所有的测试都需要被关联到一个唯一的标识号码。从最低程序上说,指派测试ID可以帮助在多种测试配置和场景中跟踪测试结果,并且它也可以将需求或用户故事与相应的测试联系起来。
对每个测试用例指派唯一的ID是最低要求,但是如果能够实现一个更大的和测试相关的属性集合,那么就可以支持更大的功能集合。
测试用例编号
这是一个分配给各项测试的全局唯一的号码。编号并不一定需要按顺序的,但它们必须是唯一的。在大的系统中,一个能自动分配唯一编号的方法是必需的。
自动化测试实验室
测试需要地方来运行。无论它是一个办公室里的10台机器还是一个在外面数据中心的上百台机器,对实验室细心的规划,包括一个测试部署策略,是非常关键的。出于效率的原因,在一组测试机器上并行地运行测试要比在一台机器上顺序地运行要更有意义。如果对测试团队来说兼容性是一个考虑因素,或者如果因为其他原因要求多样化的环境,那么需要在一个合理时间内完成自动化测试的机器的数目增长得很快。
一个有效配置的测试实验室要求有足够可用的机器来允许自动化测试可以在一个合理的时间内完成而且没有很多利用率太低的机器。测试实验室要求计算机、空间、电力和冷却设施。为了最好地抵消运行测试实验室的开销,一个自动化测试实验室里的机器应该越忙越好。除了有效地利用测试实验室的机器来运行自动化测试,另一个策略是用实验室里的机器来运行测试的扩展版本、压力测试,或者介于自动化测试运行之间的特定客户场景。
部署测试台
测试实验室可能既有物理的机器又有虚拟的机器。部署虚拟机器通常就像把合适的虚拟硬盘驱动复制到宿主系统上去那样简单。对物理的机器来说,装一个干净版本的操作系统外加更新和任何必需的测试应用程序对实际的测试自动化来说太花费时间。如果测试需要一个干净的准备就绪的操作安装,对于操作系统和应用程序安装来说,一个更有效的方法是通过一个可以快速把一个操作系统外加相关程序的镜像写到磁盘上去的磁盘镜像工具。任何实验室中的电脑在被准备进行测试的时候就是它们不在测试的时候。花上2个小时的安装过程来运行10分钟的测试是只有很少人才会认为有效率的事情。将测试台准备时间最小化是增加实验室效率的一个关键部分。
测试分配
一旦测试实验室里的电脑准备好了,下一个部分(并且有可能是整个系统最重要的一部分)是部署和执行测试。如果你投资了一个放满上百台机器的测试实验室,你想要确保机器的高使用率——比如,尽可能减少那些机器在等待运行测试指令的空闲时间。
根据实现,第一步是查一下清单看测试用例或配置是否对测试可用。当由测试用例开始时,下一步是开始在测试机器上部署操作系统和应用程序配置。当由可用的配置开始时,第二步是将没有运行的测试用例与当前的一组机器配置进行匹配。总的来说,前者在当测试进行在一组已知的比较少的配置上时比较好,而后者在处理一个比较多的配置时会稍微方便一些。
一台或更多的机器(有时称为测试控制器)在负责把测试分配给测试实验室中等待的机器。这些机器实现了一个用套接字、消息队列或者另一个多机器感知同步机制的连接系统。
一旦测试电脑的准备完成了,系统把测试复制到了目标机器,然后测试执行。一个测试控制器等待测试完成(挂起或崩溃),然后从测试电脑中获取日志文件。这个测试控制器可以直接把日志文件解析出结果,但是更通常的是它把日志文件发回给测试用例管理器或另一台电脑来解析和分析。
在自动化系统中的另一件要考虑的事情是一个可以知道测试什么时候完成的机制。等一段固定的时间是危险的,因为测试在不同的系统上会花不同的时间来完成。另一方面,简单地给一个测试大量的时间来完成往往意味着测试机器将会不同程度地闲置。对于通过的测试,简单的解决方案是让测试插件当测试进程退出的时候给控制器发信号。此外,如果测试在指定的时间内没有完成,那么把一个最大时间长度和一个测试相关联会触发控制器去从测试机器获取结果和崩溃时的日志信息。
失败分析
如果你测试全部感兴趣的地方,那么它们中的一些注定会失败。一些失败可能是因为产品的bug,其他一些则可能是测试里的错误引起的。在相关方面的一些失败可能是由相同的bug引起的。如果你在多个配置上运行一个单一测试,那么它可能在多个(或者所有的)配置上失败。如果相同的测试(例如,“验证widget控件激活菜单项”)会同时在Windows XP和Windows Vista上失败,失败分析可以分析日志文件或其他测试辅助。如果它决定了是由同一个问题引起了这两个失败,那么它就会仅仅汇报一个失败。
如果一个团队有许多测试和相当大的失败数目,这个测试团队将会以花费一大堆时间在调查失败的测试上而告终——如此多的时间,实际上,以致他们只剩下很少的时间来进行实际的测试。不幸的替代这个分析无力的方法就是简单地掩饰失败调查和报最好的希望(实践经验往往就是以一个重大的bug在客户手中发现而告终)。
解决这一困境的方法就是把分析和测试失败的调查自动化。使分析能有效进行的首要事情是对所有的测试有一致的日志实现。失败分析系统实现的匹配算法能在失败测试的日志中查找相似点和识别可能被同一个原因触发的失败。失败分析系统还可以为任何造成崩溃的测试自动分析调用栈或者其他调试信息。
当测试失败了,系统能创建一个新的bug报告或者更新一个已有的报告,这取决于这个失败是一个新的问题或是已知的(见图8-3)。一个对大规模测试自动化极好的投资回报要求自动化所有阶段的集成、登记和bug跟踪系统。一个成功的解决方案大大地减少了对人工干预分析测试结果和失败的需求。
测试报告
从管理层的角度来看,测试结果可能是测试团队最重要的工件了。当前的和相关的测试结果是一个自动化系统的另一个主要方面,并且测试结果是当前的、准确的和能简单得到的是很关键的。
自动化系统在报告中的角色是保证前面讨论的那些项目是可能的。测试结果的跟踪和标记是必要的。对任何新的失败(自动失败分析应该能过滤出之前测试中发现的错误),关于错误的信息(诸如调用栈和日志文件)需要能随时准备和快速地获取到,才可以使测试人员可能有效地诊断问题。
往期系列文章