用 STAF/STAX + LAMP 实现多任务的自动化测试框架

发表于:2009-10-10来源:作者:点击数: 标签:
STAF/STAX 是由 IBM 开发的自动化 测试 运行环境,由于其跨平台和扩展性强的特点,在各种测试工作中被越来越多的使用,但是它也存在流程复杂,操作不便等缺点。而 LAMP 是基于 Linux ,Apache,MySQL 和 PHP 的 开源 网络开发平台,PHP 可用 Perl 或 Python

STAF/STAX 是由 IBM 开发的自动化测试运行环境,由于其跨平台和扩展性强的特点,在各种测试工作中被越来越多的使用,但是它也存在流程复杂,操作不便等缺点。而 LAMP 是基于Linux,Apache,MySQL 和 PHP 的开源网络开发平台,PHP 可用 Perl 或 Python 代替。Linux+Apache+MySQL+Perl/PHP/Python 常被放在一起使用,来搭建动态网站或者服务器的开源软件,他们拥有了越来越高的兼容度,共同组成了一个强大的 Web 应用程序平台。LAMP 具有搭建快捷,界面友好等特点。为了提高测试运行效率,提供良好的使用体验,我们开发了基于LAMP+STAF/STAX 的自动化测试框架并应用在 WVS 产品的测试中。该框架中前端是 LAMP 实现的动态网站,后端是 STAF/STAX 服务及脚本。我们还利用 STAF 的参数导入特性实现了多任务的自动执行。本文将对基于 LAMP+STAF/STAX 的自动化测试框架的功能特性,体系结构,以及应用在WVS 产品测试中的拓扑结构,设计实现和配置使用进行介绍和分析。

功能特性

该框架不仅利用了 STAF/STAX 的自动化功能,还利用了 LAMP 的强大 Web 应用能力,提供了丰富的自动化测试功能和可扩展特性。总体来说,主要有以下功能特性:

  • 上层应用逻辑和底层自动测试实现松耦合
  • 自动化测试功能可扩展性强,支持多任务执行
  • 支持远程程序调用
  • 方便友好提交测试任务
  • 可实时监控测试任务和 STAX 运行情况
  • 历史测试记录可维护




回页首


体系结构

该框架符合 MVC 的三层结构,主要的功能模块都在控制层,包括提交和监控测试任务,监控 STAX 运行,支持多任务执行,维护历史测试记录等。在该框架中,表示层和控制层的功能实现是以 PHP 形式存在,采用 MySQL 作为数据容器,Apache Server 作为 Web Server,另外在控制层中关于自动化测试的功能实现是以 xml 形式存在,它是被实现层中的 STAF/STAX 所调用。它的体系结构如下图所示:


图 1. LAMP+STAF/STAX测试框架结构图
LAMP+STAF/STAX测试框架结构图

拓扑结构

我们把该框架应用在了 WVS 产品的自动化测试中,在这个测试中,我们需要更改 WVS 的配置并对其进行重启,执行 Tester 机器上的脚本,向 Voice Enabler 所在的机器发送 Sip 请求,然后 Voice Enabler 会建立与 WVS 机器的 RTSP 连接以获取其语音识别和语音合成服务,测试结束后再从 WVS 机器拷贝日志进行分析。我们希望这一切都用 STAF/STAX 控制自动完成。因此在所有的机器上都安装了 STAF。另外我们把对测试进行前端控制的 LAMP 软件和代码也配置在了 Tester 机器上,以充分利用其系统资源。对应的,Tester 机器的 STAF 需要安装 STAX 服务来运行本地的 STAX 脚本。该系统的部署图如下所示:


图 2. LAMP+STAF/STAX 网络拓扑
LAMP+STAF/STAX 网络拓扑




回页首


设计实现

关于 LAMP 的部分,这里会给出一些应用示图和代码示例,关于 STAF/STAX 中的一些功能给出代码示例,仅供参考。

提交测试任务:

该应用提供了 GUI 方式的任务提交,在提交表单中可以选择平台,版本信息,需要运行的用例类型,任务的名字等,方便快捷。如下图所示


图 3. 提交测试任务页面
提交测试任务页面

 

维护历史测试记录:

该应用中的测试记录都被存储在了 MySQL 数据库中,可以进行浏览,查询,删除等操作,方便测试者察看以前的测试信息,辅以参考。如下图所示。


图 4. 任务列表查看页面
任务列表查看页面

多任务支持:

如前所述,测试任务的执行是由 STAX 模块来完成的。本框架应用中的 STAX 执行模块包括三个主要的 STAX 脚本文件,分别是 queuemgr.xml,testexecute.xml 和 funcdef.xml。其中 funcdef.xml 定义了 testexecute.xml 中要用到的功能函数,如判断操作系统类型和版本、读写文件、启动或停止应用服务器和发送HTTP请求等。testexecute.xml 里定义了测试执行的流程和各种测试变量,它执行时会首先导入记录了当前测试任务的参数的 xml 文件,然后用这些参数初始化各种测试变量并执行相应测试功能,最后在测试任务完成时将任务参数文件转移到测试日志所在目录。queuemgr.xml 定义了一个独立的 STAX 队列管理任务,它在启动后循环检查测试任务参数文件所在的目录,如果目录非空,则选择最早的任务文件名作为运行参数让 STAX 执行 testexecute.xml。此外,它还负责测试计时、错误处理和延时等待等工作。其运行流程如下图。


图 5. 任务列表处理流程
任务列表处理流程

下面给出了 queuemgr.xml 中定义的函数 check-queue 的代码。它被 queuemgr.xml 的 main 函数在初始化各种全局变量后调用。实现自动执行任务队列的 STAX 脚本代码如下。


清单 1. queuemgr.xml 中的 check-queue 函数
<function name="check-queue">    <sequence>   <block name="'Queue Manager'">    <sequence>     <stafcmd name="'Check Queue'">      <location>'local'</location>      <service>'FS'</service>      <request>'LIST DIRECTORY %s TYPE F SORTBYNAME' % queueDir</request>     </stafcmd>     <script>dirList = STAFResult</script>               <script>taskCount = len(dirList)</script>     <script>                  if (taskCount != 0):               # skip an empty list       taskParam = dirList[0]               # get first entry                   else:       taskParam = "empty"                             </script>     <if expr=" taskParam != 'empty'">      <if expr=" lastTaskParam != taskParam">       <sequence>        <if expr="TestRunInProgress[0] == 0">         <script>          TestRunInProgress[0] = 1          TestRunStartTime[0] = now()         </script>        </if>        <script>TestRunCtr[0] = TestRunCtr[0] + 1</script>        <script> lastTaskParam = taskParam </script>        <script>lastTaskParamJobID = taskParamJobID </script>        <log>'QueueMgr: Executing taskParam %s' %(taskParam)</log>        <stafcmd name="'Executing Task: %s' % taskParam">         <location>'local'</location>         <service>'STAX'</service>         <request>'EXECUTE FILE %s CLEARLOGS JOBNAME %s SCRIPT. " taskParam=\'%s\'" WAIT %s' %(TestExecuteFile, taskParam, taskParam,gblTestExecutionTimeoutMS)</request>        </stafcmd>        <script> taskParamJobID = STAFResult</script>        <log>'QueueMgr: taskParam %s  JobID = %s' %( taskParam, taskParamJobID)</log>        <if expr="RC != STAFRC.Ok">         <sequence>         <log>'QueueMgr: Execute Test with Param File %s failed - RC: %s  STAFResult: %s'                   %( taskParam,RC,STAFResult)</log>          <terminate block="'main'"/>         </sequence>        </if>       </sequence>       <else>        <sequence>        <log>'QueueMgr: *** TERMINATING Queue Manager *** Task File %s is the same as the                last one' %( taskParam)</log>         <log>'QueueMgr: Please check the completion status of Test Record %s Job ID %s and Re-Start the Queue Manager' %( lastTaskParam, lastTaskParamJobID)</log>         <terminate block="'main'"/>         </sequence>       </else>      </if>      <else>       <sequence>                    <if expr="TestRunInProgress[0] == 1">         <sequence>                           <script>            TestRunInProgress[0] = 0            TestRunStopTime[0] = now()            testTime = (TestRunStopTime[0] - TestRunStartTime[0])            testHrs = int((testTime) / 3600)            testMin = int((testTime - (testHrs * 3600)) / 60)            testSec = int((testTime - (testHrs * 3600)) - (testMin * 60))            TestRunCompletionDateTime = strftime('%a %b %d %Y %H:%M:%S', localtime())           </script>           <log>'All tests have been run; the testqueue is empty'</log>            <log>'Test Run Completed: %s' % TestRunCompletionDateTime</log>           <log>'%d Test Tasks Were Completed In %d Hrs %d Min %d Sec'                   % (TestRunCtr[0],testHrs,testMin,testSec)</log>                              <script>TestRunCtr[0] = 0</script>           <terminate block="'main'"/>          </sequence>        </if>            <block name="'Queue Check Delay'">         <stafcmd name="'Checking TestQueue Every 5000 Sec' % gblCheckQueueDelayTimeSec">          <location>'local'</location>          <service>'DELAY'</service>          <request>'DELAY 5000'</request>         </stafcmd>                  </block>       </sequence>      </else>     </if>     <block name="'Queue Process Delay'">      <stafcmd name="'Checking TestQueue 5000 Sec After Last Task'">      <location>'local'</location>      <service>'DELAY'</service>      <request>'DELAY 5000'</request>     </stafcmd>              </block>   </sequence>  </block> </sequence></function>

代码中第一个延时等待是对空任务队列的查看周期。测试执行人员根据个人习惯有时候希望先启动任务队列执行任务,再生成测试任务参数文件。这时查看队列的循环不能在第一次遇到队列为空时就退出,而是要不断反复查看任务队列。如果在循环之间不加延时,会造成进程对 CPU 开销过大,影响其他进程。第二个延时是前后两个测试任务执行之间的延时。这是为了让刚结束的测试进程有足够时间释放各种资源和执行多个文件操作,如日志文件和测试参数文件的转移。

每次循环中获得测试任务文件列表时要判断第一个任务参数文件是否在上次循环中已经尝试执行过。若是,则上次任务肯定没有正常结束,否则应该将该任务文件转移到任务结果文件夹中。这时应该中止任务队列处理进程,提示测试执行人员查看 STAX 日志排除错误。

生成任务参数文件并启动任务队列执行的 PHP 代码如下。该部分代码在测试者提交了图 3 所示的测试任务配置表单后执行。


清单 2. 生成任务参数文件并启动任务队列的代码
$isTestStarted = false;$testQueueDir=opendir("$testQueuePath");			while($fileName=readdir($testQueueDir)){					if ($fileName!="." and $fileName!="..") {		$isTestStarted = true;				break;	}}//Here should be the code to create a parameter file for this task, using parameters setby user from the web UI.if(!$isTestStarted){  exec("STAF local STAX EXECUTE FILE /usr/local/staf/xml/queuemanager.xml CLEARLOGS");}header('Location: / viewTestList.PHP');

在这里我们并没有去检查任务处理进程是否在系统中存在,而是根据任务文件文件夹是否为空来判断。这一判断是基于若队列中有未执行完的任务,则应该有队列处理进程在进行处理的简单假设。当然偶尔也会有测试任务出错,任务处理进程非正常中止的情况发生,使得该假设失准。因此,我们要在 PHP 代码中查询任务处理进程的日志,判断其运行状态,并在页面中向测试执行人员显示出来。如果任务文件夹中尚有文件未执行,而队列处理进程又处于停止状态,就要提示测试人员排查错误并手动重启任务队列处理进程。

STAX 任务启动后,我们也可以随时让 PHP 代码执行exec("STAF local STAX TERMINATE JOB $JobID")来中止任务编号为 JobID 的 STAX 任务。

监控 STAX 运行情况:

STAX 一旦出错,意味着任务无法运行,如果能够实时监控 STAX 任务运行状态,可提高可靠性


清单 3. 监控 STAX 任务状态
exec("./viewStaxLog.sh $staxJobID 2>&1", $outPut);$isStopped = false;foreach($outPut as $outputline){	$pos = strpos($outputline, "Stop   JobID:");	if($pos !== false){		$isStopped = true;	}}if($isStopped){	echo "<fond color=\"blue\">Stopped</font><br>";}else{	echo "<fond color=\"red\">Running</font><br>";}

上面清单中调用了查看 STAX 日志的 shell 脚本。STAX 日志分为两种,一种是系统对任务运行情况和错误的自动记录,另一种是测试开发人员在 STAX 任务脚本中用 <log></log> 标签主动记录的日志。可以通过 STAF 命令实时查询任何 STAX 任务的日志。在获得日志后可以根据日志中的关键字(如上面代码中的“Stop JobID:”)判断 STAX 任务的状态。

STAX 的日志可以用 STAF 命令进行查询,其代码如下。


清单 4. 查询 STAX 日志
if [ $1 = “user” ]thenstaf local log query machine mytest.cn.ibm.com logname STAX_Job_$2_Userelsestaf local log query machine mytest.cn.ibm.com logname STAX_Job_$1fi

远程程序调用:

在测试过程中,可以让 STAX 远程执行要运行的程序,这里给出实际应用中经常会调用 shell 脚本的示例,其 STAX 代码如下。


清单 5. STAX 远程调用 shell 脚本
<process>   <location>'local'</location>   <command  mode="'shell'" >'"./%" result %s %s'                                     % (testScriptName,testParam1,testParam2)</command>   <workdir>'%s' % testScriptDir</workdir>   <stderr mode="'stdout'"/>   <returnstdout/></process><if expr="RC != 0">   <log>'Error: RC=%s, STAXResult=%s, Error running test script'          % (RC, STAXResult)</log>   <else>      <log>'Running test script. STAXResult=%s' % (STAXResult)</log>   </else></if>

分析测试结果:

STAX 使用 Python 处理其脚本中的表达式。为了便于文本分析,使用者可以在 STAX 脚本中嵌入 Python 脚本。用这种方式可以方便地利用 Python 强大的正则表达式处理能力。下面的代码示范如何从日志文件中提取相关文字并进行对比判断。

<stafcmd>   <location>'%s' % logServer</location>   <service>'fileman'</service>      <request>'grep file "%s" machine "%s" for "%s" last CODEPAGE ascii'                % (testLogName,logServer,testCaseName)</request></stafcmd><!—- Some other code here --><script>   import re   import string   result = str(STAFResult[0])   testCaseMatch = re.search("%s %s"       % (testCaseName.upper(),expectedResult.upper()),result.upper())</script>

配置使用

配置这样一个自动化测试框架,需要安装 Apache Server,MySQL,PHP,如何安装该环境,这里就不赘述。我们开发的测试框架由于其功能比较多,也需要在测试中不断的更改配置,有时还要增加测试内容。为了便于其配置,我们将PHP代码中有可能需要修改的变量都放在一个单独的 PHP 文件中,而与测试用例相关的变量用 PHP 数组的形式存放在另一个 PHP 文件中。所有要用到这些配置的 PHP 文件对其进行包含。

总结

LAMP 是功能强大的 Web 应用程序平台,STAF/STAX 具有很好的自动测试功能,把二者结合起来就可以形成更加灵活可靠,易于功能扩展的新的自动化测试框架,本文也通过在 WVS 产品测试中使用该框架从而获得了很好的测试效果。

原文转自:http://www.ltesting.net