技术开发 频道

提高自动化测试套件的可维护性

  4. 使用基于框架的架构

  虽然框架通常与一个或一个以上的数据驱动测试策略一同使用,但它本身却提供了一种完全不同的方法。Tom Arnold(LAWST成员之一)在它的书和课程中论述了这种方法。

  框架通过提供共享函数库中的一套函数,把应用程序从测试脚本中分离。这样,测试脚本编写者在处理这里函数时,就可以把它们视为测试工具的编程语言的基本命令。因此,他们能单独编写软件的用户界面脚本。

  例如,一个框架编写者创建了函数openfile(p)。该函数用来打开文件p。它可以通过下拉文件菜单、选择打开命令、复制文件名到文件名域、点击OK按钮关闭对话框来完成操作。此外,这个函数也可以变得更复杂一些,比如,添加可扩展的错误处理功能。它能检查文件p是否已经被打开,或者记录打开文件的尝试以及对结果做日志。该函数还可以用一个命令快捷键,而不是菜单导航来弹出文件打开对话框。如果你的测试程序涉及到一个应用编程接口 (API)或宏语言,那么该函数或许能调用一个单独的命令,并把文件名和路径作为参数传递给它。函数的定义经常在变化。但只要openfile(x)能打开文件x,脚本编写者就不必在意。

  很多函数库中的函数在一些应用程序中依然有用(或者当它们被设计成可移植的时,也会很有用)。不要指望100%的可移植性。例如,openfile()的某个版本可以在每个应用程序中使用标准文件打开对话框,但你可能需要为那些有定制对话框的程序设计额外的版本。

  框架包括若干类函数,从简单应用程序或工具功能的打包到处理完整任务的复杂脚本。以下是一些基本的类型:

  a. 定义应用程序的每种特性

  你可以通过编写函数来选择菜单选项,弹出对话框,设定变量值或发布命令。如果用户界面改变了其中的一种工作方式,那么你也就改变了函数的工作方式。而当你重新编译或重新链接时,任何一个用该函数编写的脚本都能自动修改。

  在处理定制控件时,框架是最重要的,比如自绘制控件。一个自绘制控件利用程序员提供的图表命令来绘制一个对话框。自动化测试工具只能辨认窗口的存在,却不能辨认里面的东西。因此,当工具并不知道按钮是否在对话框中时,如何让它点击这个按钮呢?而当工具并不知道列表框是否在那里时,又如何让它选择其中的表项呢?或许,你可以用某种小技巧来选择列表中的第三项吧,但是你如何选择一个出现在可变长度的列表中任何位置的表项呢?还有一个问题:当改变视频协议后,你如何像往常那样处理这些不可见的按钮和列表框,以及其他的用户界面元素呢?

  在LAWST会议上,我们谈到用基于组装件的组装件来处理这类问题。有一些与会者估计,他们把自动化开发的一半时间都用来处理由定制控件所带来的问题了。

  这些组装件对于脚本编写者来说,是一系列复杂的、难以维护且越来越严重的干扰。之所以称它们是干扰,是因为它们不是由正在测试的程序本身引起的,而是由工具引起的。因此,它们使测试人员把精力放在工具的缺点上,而不是放在找出并报告程序本身的缺点上。

  如果你必须使用自绘制控件,那么封装应用程序的每种特性很可能是你构建框架的最紧迫且繁重的任务。这可以把每个组装件隐藏到一个函数中。如果要使用一个特性,程序员就调用该特性,而不必考虑组装件的存在。而如果用户界面发生改变,则可以在不影响单个脚本的情况下重建组装件。

  b. 定义工具的程序语言的命令或特性

  自动化工具都有一个脚本语言。你会发现,通过包裹每个命令来增加一个间接层的做法非常便捷。所谓包裹,就是一个被创建在另一个函数周围的例程。这非常的简单,很可能仅仅只需调用打包函数即可。而且,你可以通过修改包裹来增加或替换函数,以避免测试工具中产生bug,或利用更新的脚本语言。

  Tom Arnold给出了wMenuSelect的例子,它是一个选择菜单的可视化测试函数。他编写了一个打包函数:可简单调用wMenuSelect的 SelMenu()。这种做法具有灵活性。举个例子,你可以修改SelMenu(),比如,添加日志功能、添加错误处理机制、添加调用内存监视器命令,或其他任何你想添加的东西。当这样做时,每个脚本都能得到这个新的功能,而并不需要额外编写代码。这种做法在强力测试、测试执行分析、bug分析报告与调试目标方面都非常有用。

  用过这种方法的LAWST成员说,该方法已经反复收到成效。

  c. 定义经常使用的概念统一的小任务

  openfile()函数是这种类型函数的一个典型例子。脚本编写者会编写上百个需要打开文件的脚本,但他只会有意识地关注少数脚本中的文件是怎样被打开的。至于其它的,他只是想要文件被迅速可靠地打开,这样,他就能继续测试他真正要测试的东西。添加一个库函数来做这些事情将会节省脚本编写者的时间,并且能改进脚本的可维护性。

  这属于直接的代码重用。与其它任何软件开发一样,在测试自动化中也有同样的需求。

  d. 定义用在若干测试用例中的更大更复杂的测试用例块

  存在着封装更大规模的命令序列的需求。然而,这样做也存在着风险,尤其是当你过多使用时。因为一个很复杂的命令序列很可能在很多测试脚本中无法重用,所以,就不值得花力气去生成它,为它写文档,并为它加入错误检查代码以期成为编写完善的库函数。此外,序列越复杂,当用户界面改变时就越需要维护。那样一来,你的库维护成本就被一组几乎不用的复杂命令决定了。

  e. 定义实用程序函数

  例如,你可以创建一个以标准方法把测试结果保存到硬盘的日志函数。你也可以创建一个编码标准,即每个测试用例都以对该函数的调用作为结束。

  每个工具都提供了它自己的一套预构建实用程序函数。这样,你可能需要也可能不需要更多额外的函数了。

  使用框架的风险

  你不能同时把所有这些命令都构建到你的函数库中。因为你没有足够多的人力。一些自动化项目之所以失败,正是因为测试人员试图创建一种终极的、无所不包的编程库。而在框架完成且可用之前,管理支持(一些人员的工作)就已经不存在了。因此,你必须权衡先后,随着时间逐渐地构建你的函数库。

  不要认为每个人使用函数库仅仅是因为它已经存在。有的人的编码风格与其他人就不同。如果你没有一个编程标准来控制变量命名、函数接口的参数顺序、全局变量的使用等等,那么在一个人看来合理的东西在另一个看来将变的不可接受。此外,有的人不喜欢使用不是他们编写的代码。而另一些人由于参与项目较晚而不知道库中的内容,于是就仓促的在没有了解库的情况下开始编程。因此,你必须管理好库的使用。

  最后,要慎重设置期望值,尤其在当你的程序员编写了他们自己定制的控件时。在发行版1.0(或你开始自动化测试的第一个发行版)中,你很可能会花费很多时间来创建一个封装了所有工作区的框架,以至你不得不编写点击按钮、选择表项、选择tab键的代码。这些工作的回报将在你最后花时间编写的发行版 2.0中体现出来。创建框架的开销很大,因此,要设置符合实际的期望值或修正你的摘要。

0
相关文章