采用 Rational Functional Tester 实现基于时间的自动化测试过程监控

郭 艳芬, 软件工程师, IBM
 
李 冬瑞, 软件工程师, IBM
 

简介: 本文针对自动化测试脚本的特点,采用 Rational Functional Tester(RFT)实现了一种基于时间的自动化测试过程监控方法。以自动化测试脚本的某一次执行时间为基准值,使用进度条来准确、直观地实时展现批量脚本执行情况,并可实现远程监控。本方法可以有效地帮助测试人员监控测试进度,预估脚本执行的剩余时间。

 

本文介绍了一种基于时间的自动化测试过程监控方法。

通过学习这篇文章,您可以了解:

  • 自动化测试脚本的特点
  • 自动化测试过程远程监控相关技术
  • 如何利用 RFT 实现基于时间的自动化测试过程监控

背景

自动化测试就是使用一个程序(测试脚本)来测试另一个程序(被测试的应用系统)功能的正确性,一次测试通常由一系列可重复使用的测试脚本组成。软件自动化测试技术的出现,大大减轻了软件测试人员的测试压力,显著提高了测试工作的效率。

IBM® Rational® Functional Tester(RFT)是一个面向对象的自动化测试工具,用于测试 Windows® 2000、Windows® XP 和 Linux 平台上的基于 Java、HTML、VB.NET、Microsoft® Windows®的应用软件。

目前监控方法的不足之处

测试人员在执行大批量的测试脚本之前,往往想要知道完成本次测试所需要的时间,以便进行工作安排或判断脚本是否能够在预定的时间内完成。但目前测试人员只能根据经验来判断脚本的执行情况,推测脚本完成还需要多长时间,有时还需要经常地查看执行情况,这无疑增加了测试人员的负担,而且依赖于测试者的经验。

在 RFT 项目中,每个测试脚本被编译后都生成一个 .class 文件,为了批量执行这些测试脚本,我们通常是编写一个测试引擎。例如,在我们的项目中我们编写了一个 CommonTestCaseRunner.java 文件,然后把需要运行的测试脚本的文件名放在一个 xml 文件中。执行测试引擎,引擎会从指定的 xml 文件取出所有的测试脚本名,然后依次调用这些测试脚本来执行。

一旦测试人员开始运行测试引擎,通常我们就是等着所有的测试脚本都被执行过之后再检查日志文件。在测试引擎执行完所有的脚本之前,我们并不知道执行的进度,也不知道这些脚本什么时候会执行完毕,而只能根据经验判断大概的时间。

一种改进的,也是目前最常用的自动化测试进度的监控方法是按照脚本的个数来展现脚本执行的过程,即:将已经执行完的脚本名字写到数据库或者一个日志文件中,这样测试人员可以通过检查数据库或者日志文件来得知测试的进度,如:总共有多少个脚本,已经完成了多少个脚本,还剩余多少个脚本。但是,由于每个脚本所需要的执行时间是不一样的,测试人员还是无法比较准确地预测剩下的脚本还需要多长时间才能完成。

基于时间的监控方法的使用场景

下面我们先来描述一下该方法的使用场景。

例如:测试人员打算用 RFT 执行如下四个自动化测试脚本:


表 1. 测试脚本列表

测试脚本编号 所需时间 ( 分钟 )
TC01 5
TC02 4
TC03 3
TC04 2

  1. 测试人员在 RFT 上运行测试引擎,在开始执行测试脚本之前,测试引擎先把预估的总的运行时间显示在一个进度条上面,本例中,测试人员可以直观地了解到正常情况下这四个脚本大概在 14 分钟(即:每个脚本所需时间的总和:5+4+3+2)后可以运行完毕。如图 1 所示。


图 1. 显示总的运行时间
图 1. 显示总的运行时间

  1. 第一个脚本 TC01 运行完毕后,我们调整进度条上的剩余时间(总时间减去 TC01 的运行时间),告诉测试人员剩余的三个脚本还需要 9 分钟(4+3+2)左右运行完成。
  2. 第二个脚本 TC02 运行完毕后,我们调整进度条上的剩余时间,告诉测试人员剩余的两个脚本还需要 5 分钟(3+2)左右运行完成。
  3. 第三个脚本 TC03 运行完毕后,我们调整进度条上的剩余时间,告诉测试人员剩余的一个脚本还需要 2 分钟(2)左右运行完成。
  4. 第四个脚本 TC04 运行完毕后,我们最终将进度条归零。

进度条的计时原理如图 2 所示:


图 2. 进度条的计时原理
图 2. 进度条的计时原理

那么这样的监控方法是否具有可行性呢?

基于时间的监控方法的可行性

下面我们来分析一下基于时间的监控方法是否具有可行性。

自动化测试具有以下特点:

  • 自动化测试较多地用于回归测试,用来验证被测系统已有的功能是否还可以正常工作。
  • 自动化测试都是重复性测试,即在开发完成之后,可多次执行。
  • 自动化测试每次执行的环境都基本相同,被测系统也是一样的。
  • 自动化测试脚本中的步骤一般都是线性执行的,即脚本内部没有太多的分支(自动化测试脚本都是手工测试脚本的实现,而手工测试脚本一般都是线性的,即从步骤 1 到步骤 N 顺序执行,较少有跳跃的分支)。
  • RFT 批量执行脚本时,是线性地逐个执行。

基于以上几点分析,我们可以设想:是否可以用测试脚本某一次执行的时间作为基准,来预测它本次执行所需要的时间呢?因为在执行的条件和环境几乎相同的情况下,同一测试脚本的执行时间应该大致相同,这也是经过我们在实际工作中的实验验证的。由此看来,这种方法是具备可行性的。

基于时间的监控方法的原理和架构

从上面的分析,我们可以想象,要实现这样的监控方法,需要解决如下的问题:

  • 如何获取每个脚本执行的基准时间。
  • 如何保存这些基准时间,并在某次具体的测试中挑选相应脚本的基准时间。
  • 监控过程中,如何依据基准时间来预估剩余时间。
  • 更进一步,如果希望实现远程监控,监控机和实际测试机之间如何通信。

下面我们来说明对于上述每个问题的解决方法。

获取脚本执行的基准时间

自动化测试对脚本的调用一般是批量调用,我们可以在每个脚本的开始和结束处加入计时器,以获得开始和结束时的时间,相减即得该脚本的执行时间。

保存基准时间

最简单的方法可以保存在 txt 文档中,但在脚本比较多的情况下 txt 格式不便于阅读,而且无法进行平均时间的计算。如果选用 Excel 格式的文件,每次执行时间可以保存在一个工作薄中,归档清晰,而且其强大的公式功能可以方便的计算平均时间,分析执行状况。所以本文选择将基准时间保存在 Excel 表格中。

实时更新剩余时间

进度条是一种简单、直观的进度监控方法,为了实时更新剩余时间,我们记录已执行的脚本个数。当一个脚本完成时,脚本程序将已执行的个数传给进度条,触动进度条值的更新。

上述方法进度条是以一个脚本的完成为基础更新的,而进度条在一个脚本的执行过程中是静止不动的,如何使其不断更新?本文采用计时器的方法,为每个当前执行的脚本启动一个计时器,在脚本执行过程中利用计时器使进度条以倒计时的方式不断更新。

远程监控的实现

进度条是根据已执行的脚本个数来更新剩余时间值的,在远程监控情况下,只需要通过 socket 通信把已执行的脚本个数传给进度条所在监控器即可。但是由于测试者可能并不希望进度条一直显示在自己的桌面上,所以进度条监控应该能够满足随时中断和启动。这就需要测试机在发送数据时先判断监控机是否启动了监控。

另外由于基准时间保存的是全部脚本的执行时间,而一次测试可能只是执行其中的一部分脚本,这就需要测试机在初次连接的时候将要执行的脚本名传给监控机,以便进度条可以读取相应的基准时间。

监控系统的整体架构

首先需要服务器端的监控机打开监控端口,等待客户机连接。客户机在建立连接的同时将要执行的脚本名发送给监控机,监控机端的进度条据此选择相应的基准时间,启动进度条监控。然后随着脚本的执行,客户机即时将已执行脚本个数发送给监控机,以更新进度条显示。监控系统的整体架构如图 3 所示。


图 3. 监控系统的整体架构
图 3. 监控系统的整体架构 

基于时间的监控方法在 RFT 里的具体实现

下面我们来介绍上面提出的解决方案在 RFT 里的具体实现。

获取脚本执行的基准时间

这里简要介绍一下我们的引擎文件“CommonTestCaseRunner”,该引擎实现了读取测试脚本列表并且依次执行测试脚本的功能。

该引擎文件的细节与本文无关,为了描述方便,这里给出关键部分的伪代码:

读取测试脚本列表;

For each 测试脚本 {
 beforeTestCase();	// 执行测试脚本之前的准备,清理工作
 runTestCase();	// 执行测试脚本
 afterTestCase();	// 执行测试脚本之后的收尾,清理工作
}

基于上述的调用方法,我们可以定义两个保存时间的长整形变量,然后在测试脚本执行之前和之后分别通过 System.currentTimeMillis() 函数获得一个毫秒计数的时间,这个时间是从 UTC 1970 年 1 月 1 日午夜开始经过的毫秒数。最后用结束时间减去开始时间(endTime – startTime)即得每个脚本的执行时间。如清单 1 所示。


清单 1. 计算脚本执行时间

long startTime; // 开始时间
long endTime; // 结束时间

public void beforeTestCase(TCREvent e) {
 startTime = System.currentTimeMillis(); // 获得开始时间
 ……
}
public void afterTestCase(TCREvent e) {
 ……
 endTime = System.currentTimeMillis(); // 获得结束时间
 // 保存 case 编号和运行时间到 excel 表中
 excelHandle.write(tcCount, (endTime-startTime));
}

保存基准时间

为方便起见,本文的设计是将数据保存到文件“C:\temp\NewRunTime.xls”中名为“new run time”的工作薄中。在初始化阶段,我们需要执行脚本,获取基准时间,然后将脚本名和相应的时间保存在表格中。存储为 Excel 文件是考虑到可以方便的计算平均值,同时还有 Java Excel 这一开源 API 可以使用。通过这个 API,Java 开发人员可以方便的读取 Excel 文件的内容、创建新的 Excel 文件、更新已经存在的 Excel 文件等。

首先需要在 RFT 的项目工程中导入 Java Excel API:“jxl.jar”,如图 4 所示。读者可以从下载部分获得这个 jar 包,也可以从参考资料中找到更多相关资料。


图 4. 导入 Java Excel API
图 4. 导入 Java Excel API

更新一个已经存在的 Excel 工作薄,主要是下面两步操作,一是构造只读的 Excel 工作薄,二是利用已经创建的 Excel 工作薄创建新的可写入的 Excel 工作薄,参考清单 2 的代码片段。


清单 2. 更新 Excel 表格

import jxl.Cell;
……

File file = new File("c:/temp/NewRunTime.xls ");
// 创建只读的 Excel 工作薄对象
Workbook readOnly = Workbook.getWorkbook(file); 
// 创建可写入的 Excel 工作薄对象
WritableWorkbook book = Workbook.createWorkbook(file, readOnly); 
// 获取名为“new run time”的工作薄
WritableSheet sheet = book.getSheet(“new run time”); 

// 获得需要写入的单元格对象,写入脚本名字和执行时间
//Number 的三个参数分别是列,行,要写入的值,下标从 0 开始
Label label = new Label(0, tcCount - 1, caseName); 
Number timeCell = new Number(1, tcCount - 1, time); 
sheet.addCell(label); 
sheet.addCell(timeCell);
// 写入 Excel 对象
book.write();
// 关闭可写入的 Excel 对象
book.close();
// 关闭只读的 Excel 对象
readOnly.close();


写入基准时间的 java 类 ExcelHandle.java 的完整代码参见本文的下载部分。

实时更新剩余时间

我们用进度条来直观地向测试人员展示测试的进度。为了尽可能地避免测试者涉及脚本代码,进度条的设计是从本地硬盘读取保存基准时间的“C:\temp\BaseLineTime.xls”文件,通过要执行的脚本名选出相应的基准时间,然后根据已完成脚本个数 tcCount 来更新进度条值。进度条的图形界面如图 5 所示。


图 5. 进度条的图形界面
图 5. 进度条的图形界面

这一部分要解决的主要问题有:

  1. 如何获得要执行的脚本名,并据此选择基准时间
  2. 如何将微秒时间转化为便于人识别的“00:00:00”时间格式
  3. 如何实现进度条在一个脚本执行过程中的持续改变

首先是选择基准时间的问题。进度条从监控机的 AcceptTcCount 类(关于该类的说明,请参考本文远程监控部分)中获得要执行的脚本序列 bucketCase

List bucketCase = com.ibm.monitor.AcceptTcCount.bucketCase;

然后读取 BaseLineTime.xls 文件的“base time”工作簿,查找相应的基准时间,将这些时间保存在 TimeArray 数组中。获得基准时间并进行处理的主要方法详见清单 3。


清单 3. 读取并计算时间

public long[] readFile(String fileName) {

 …… // 省略构建工作簿对象 wb 部分
 
 // 获得存储基准时间的工作簿
 Sheet sheet = wb.getSheet("base time"); 
 // 获得 base line 中保存的脚本总数,也即 excel 中的行数
 int caseSum = sheet.getRows();

 // 初始化时间数组
 long[] timeArray = new long[bucketCase.size()+1]; 
 // 因为进度条的值从 0 开始,所以数组第一个值为 0
 timeArray[0] = 0;

 int caseNum=0; // 要执行的脚本序号
 
 // 找出要执行的脚本,并将其基准时间存在 timeArray 数组中 
 for(Iterator it = bucketCase.iterator();it.hasNext();){
 caseNum++; 
 String caseName= it.next();
 for (int i = 0; i < caseSum; i++) {
 // 获得第一列数据(脚本名字)
 Cell cell_0 = sheet.getCell(0, i);
 
 // 如果是要执行的脚本,则保存其基准时间到 timeArray,否则跳过
 if(cell_0.getContents().equals(caseName)){
 Cell cell_1 = sheet.getCell(1, i);
 // 将 String 类型的时间转化为 long 型
 timeArray[caseNum] = Long.parseLong(cell_1.getContents()); 
 }
 }
 }
 
 // 计算时间的累加和
 for (int i=1;i

其次是转化微秒时间的问题。我们获得的基准时间是微秒时间,需要将其转化为易于人识别的时分秒形式,这里通过 computTime() 函数实现,详见清单 4。


清单 4. 将微秒时间转化为“00:00:00”形式

public String computeTime(int millTime) {
 seconds = (int) millTime / 1000;
 if (seconds > 60) {
 minutes = seconds / 60;
 seconds = seconds % 60;
 } else
 minutes = 0;

 if (minutes > 60) {
 hours = minutes / 60;
 minutes = minutes % 60;
 } else
 hours = 0;
 String remainTime = "Remaining time: " + format(hours) + ":"
+ format(minutes) + ":" + format(seconds);
 return remainTime;
}


其中“hours, minutes, seconds”分别为 int 类型的时分秒时间。format() 函数用于将个位数的时间值转化为两位数的“00”形式,具体转化方法详见清单 5。


清单 5. 将时间格式统一为“00”形式

public String format(int time){
 String formatedTime = Integer.toString(time); 
 DecimalFormat df = new DecimalFormat("00"); 
 if(time<10 ){
 formatedTime = df.format(time);
 }
 return formatedTime; 
}


最后是进度条值的持续改变。通过 run() 函数在一个脚本执行完毕后更新进度条值:


清单 6. 进度条值的更新

public void run(int tcCount) {
 // 如果脚本的本次执行快于基准时间,则停止上一个脚本的计时器,重新开始计时 
 if(timer.isRunning()) timer.stop();
 
 this.tcCount = tcCount;
 // 计算剩余微秒时间
 int millTime = (int) (timeArray[arrayLength] - timeArray[tcCount]);

 // 设置进度条显示时间
 bar.setString(computeTime(millTime));

 // 设置进度条值
 bar.setValue((int) timeArray[tcCount]);

 // 启动计时器
 timer.start(); 
}


其中 timer 是一个 javax.swing.Timer 类型的计时器,在进度条初始化时启动,用于控制进度条在单个脚本执行过程中倒计时。timer 的定义如下:

timer = new Timer(1000, this);

这里用“this”是因为进度条扩展了 ActionListener 接口(下面您将看到它还扩展了 ChangeListener 接口),timer 控制每隔 1000 微秒也就是 1 秒进度条的值改变一次,实现倒计时的效果。其触发事件见清单 7 的代码。


清单 7. timer 计时器触发的事件

public void actionPerformed(ActionEvent e) {
 int value = bar.getValue();

 // 如果是最后一个脚本,无需再更新进度条,关闭计时器
 if (tcCount == arrayLength)
 timer.stop();
 else {
 if (value < timeArray[tcCount + 1]) {
 bar.setValue(value += 1000); // 以 1 秒的速度增加
 bar.setString(computeTime((int) (timeArray[arrayLength]-value)));
 } else {
 timer.stop(); 
 }
 }
}


从清单 7 也可以看出,timer 在两种情况下会自己停止,一是当前是最后一个脚本,也即脚本已经全部执行完毕(您应该还记得在脚本执行完毕后才会将已执行数目传给进度条吧?);二是该脚本的本次执行时间长于基准时间,它会在基准时间倒计时完毕后停止,等待该脚本执行完毕后再开始下一个脚本的倒计时。清单 6 显示了 timer 被强制停止的情形,也就是该脚本的本次执行时间短于基准时间。

您应该注意到了进度条还有一个显示测试完成百分比的 label(图 5 中“Completed 60% of the task”),它的更新通过给进度条注册 stateChanged() 监听,一旦进度条的值更新,label 也随之更新。这就需要 ProgressBar.java 扩展 ChangeListener 接口,实现其抽象方法 stateChanged()


清单 8. 进度条的 stateChanged 事件

public void stateChanged(ChangeEvent e1) {
 int value = bar.getValue();
 if (e1.getSource() == bar) {
 label.setText("Completed " + (int) value * 100 / timeArray[arrayLength] 
 + "% of the task");
 }
}


最终实现进度条图形界面并实时更新时间的 ProgressBar.java 类结构如图 6 所示。


图 6. ProgressBar 的类结构
图 6. ProgressBar 的类结构

ProgressBar.java 的完整代码参见本文的下载部分。

远程监控

远程监控主要是考虑到自动化测试一般都是在远程测试机上执行,为了方便测试人员监控测试进度,我们设计成让测试人员可以不用登陆远程测试机,在本机即可查看测试执行情况。这个功能的实现由作为客户端的测试机和作为服务器的监控机配合完成。

客户端

客户端的测试机负责连接监控机,在初始化连接时将要执行的脚本名发给监控机,监控机据此选择相应的基准时间。然后随着脚本的执行将已执行脚本个数 tcCount 发送给监控机。同时如果监控机端关闭进度条断开连接,客户端要更新相应的状态,并在需要发送 tcCount 前尝试再次连接。


清单 9. 连接监控机

Socket s = null;
DataOutputStream dos = null;
DataInputStream dis = null;

public boolean connect() {
 try {
 // 此处须将 IP 地址设置为监控机 IP
 s = new Socket("127.0.0.1", 8888);

 // 建立输入输出流
 dos = new DataOutputStream(s.getOutputStream());
 dis = new DataInputStream(s.getInputStream());

 // 将脚本名发给服务器端
 List bucketCase = new ReadXML().readXml();
 for(Iterator it = bucketCase.iterator(); it.hasNext();){
 String caseName = it.next();
 dos.writeUTF(caseName);
 dos.flush();
 }
 // 发送 0 表示脚本名数据传递完毕
 dos.writeUTF("0");
 dos.flush();

 // 启动对服务器的监控线程
 Thread tRecv = new Thread(new RecvThread());
 tRecv.start();

 } 
 …… // 省略异常处理部分
 
 return true;
}


注意其中发送脚本名部分,通过 ReadXML 类的 readXml() 函数读取保存脚本的 xml 文件。至于如何读取 xml 文件不在本文讨论范围内,有兴趣的读者可以从本文的下载部分获得这个 ReadXML 类。在这里您只要理解通过这个类可以提取要执行的脚本名,并将其存储在字符串类型的列表中即可。

从清单 9 中也可以看出对监控机端的监控通过一个私有类 RecvThread 实现,该类扩展了 Runnable 接口,如果监控机关闭端口,则捕获异常,设置连接标示 ifConnect 值为 fasle


清单 10. 判断监控机是否断开连接

private class RecvThread implements Runnable {
 public void run() {
 while (ifConnect)
 try {
 ifConnect = dis.readBoolean();
 } catch (SocketException e) {
 ifConnect = false;
 System.out.println("1: closed connect,bye!");
 } catch (EOFException e) {
 ifConnect = false;
 System.out.println("2: closed connect,bye!");
 } catch (IOException e) {
 ifConnect = false;
 System.out.println("3: closed connect,bye!");
 }
 }
}


最后,发送已完成的脚本个数给监控机端。


清单 11. 发送已完成的脚本个数 tcCount

public void send(int tcCount) {
 try {
 dos.writeInt(tcCount);
 dos.flush();
 } catch (IOException e) {
 e.printStackTrace();
 }
}

SentTcCount.java 的完整代码参见本文下载部分。

监控机端

监控机端在需要监控的时候开启“8888”端口(读者也可自行选用其它端口),等待客户端连接。在初始化客户端连接时接收客户端发送的脚本名列表,然后由进度条根据这个列表选择基准时间。最后创建进度条,建立和客户端的连接。当接收到客户端发来的 tcCount 时,更新进度条值。

首先启动“8888”端口:

ServerSocket ss = new ServerSocket(8888);

然后建立 socket 连接:

Socket s = ss.accept();

在初始化创建客户端连接时接收脚本名,并将其存在字符串列表 bucketCase 中,如果收到“0”则表示脚本名列表发送完毕,可以初始化进度条。进度条在初始化时会调用 bucketCase 去读取基准时间。


清单 12. 创建客户端连接

public Client(Socket s) {
 this.s = s;
 try {
 dis = new DataInputStream(s.getInputStream());
 dos = new DataOutputStream(s.getOutputStream());
 ifConnect = true;
 	
 // 在客户端初始化时接收脚本序列 , 这里假设脚本名字都长于 4 个字符
 String readIn = dis.readUTF(); 
 while(!readIn.equals("0")){ 
 bucketCase.add(readIn);
 readIn = dis.readUTF();
 }
 
 } catch (IOException e) {
 e.printStackTrace();
 }
 
 // 接收完脚本名,创建进度条
 bar = new ProgressBar();
 bar.run(0);
}


清单 12 的 Client() 函数是监控端 AcceptTcCount 的内部类的构造函数,该类扩展了 Runnable 接口,重载 run() 方法实现在脚本执行过程中接收脚本执行个数,详见代码清单 13。


清单 13. 接收已完成的脚本个数 tcCount

public void run() {
 try {
 while (ifConnect) {
 int tcCount = dis.readInt();
 bar.run(tcCount);
 }
 } catch (EOFException e) {
 ifConnect = false;
 System.out.println("1: Client closed!");
 } 

 ……
}


AcceptTcCount.java 的完整代码参见本文的下载部分。

远程监控的调用方法

测试人员在 RFT 中开始运行批量的测试脚本之后,可在任何一台远程机器上实施监控。脚本开发人员可以先将 ProgressBar.java 和 AcceptTcCount.java 导出为可执行的 jar 包,连同保存基准时间的 Excel 文件一起,拷贝到在负责监控的机器上并启动或关闭。若关闭后重新启动,需要等一个测试脚本执行完毕后进度条才能刷新。

注意在导出 jar 包的过程中要选择启动配置,通过 AcceptTcCount.java 调用 ProgressBar.java。如图 7 所示。我们建议创建只包含这两个文件的 java 工程然后导出 jar 包,以避免导出的 jar 包文件过大。


图 7. 将服务端文件导出为可执行 jar 包
图 7. 将服务端文件导出为可执行 jar 包

本文所用到的类之间的结构如图 8 所示:


图 8. 类图结构
图 8. 类图结构

本例中,我们要先修改 SentTcCount.java 中要连接的监控机 IP 地址和端口,在实际应用中,我们可以把该地址和端口放在一个独立的配置文件中(例如:ProgressServer.ini),以避免直接修改源代码。

Socket s = new Socket("127.0.0.1", 8888);

远程监控的调用方法参见代码清单 14。


清单 14. 远程监控调用方法

public class CommonTestCaseRunner extends CommonTestCaseRunnerHelper
{
 long startTime; 
 long endTime; 
 int tcCount = 0;
 // 获得要执行的脚本 
 List bucketCase = new ReadXML().readXml(); 
 // 创建 ExcelHandle 对象
 ExcelHandle excelHandle = new ExcelHandle();
 // 创建客户端对象
 SentTcCount stc = new SentTcCount();
 boolean ifConnect = stc.connect();

 public void beforeTestCase(TCREvent e) {
 // 获得开始时间
 startTime = System.currentTimeMillis();
 
 ……
 }

 public void afterTestCase(TCREvent e) {
 ……

 // 已执行脚本个数加 1
 tcCount++;
 // 获得结束时间
 endTime = System.currentTimeMillis();

 // 判断客户端和监控机是否连接,如果没有连接则尝试重新连接
 ifConnect = SentTcCount.ifConnect;
 if(ifConnect)
 stc.send(tcCount);
 else{
 ifConnect = stc.connect();
 if(ifConnect)
 stc.send(tcCount);
 }

 // 保存脚本名字和运行时间到 excel 表中
excelHandle.write(tcCount,bucketCase.get(tcCount-1),(endTime-startTime)); 
 }

 public void afterWholeBucketRun(TCREvent e) {
 ……
 
 // 当所有脚本都执行完毕时,关闭和监控端连接
 if(ifConnect)
 stc.disconnect();
 }
}


当然,如果认为基准时间已经足够准确,可以不用每次测试都保存执行时间。不过我们不建议这么做,因为通过和基准时间的对比有助于更全面的了解测试执行情况。

监控效果

基准时间保存在监控机端的“C:\temp\BaseLineTime.xls”文件中,文件内容如图 9 所示,第一列是脚本名,第二列为微秒格式的执行时间。其中有两个不需要执行的脚本。


图 9. 基准时间
图 9. 基准时间

下面是进度条各个不同状态下的效果图:


图 10. 进度条效果图—开始测试
图 10. 进度条效果图—开始测试

图 11. 进度条效果图—测试中
图 11. 进度条效果图—测试中

图 12. 进度条效果图—测试完成
图 12. 进度条效果图—测试完成

获得的新一次的执行时间如图 13 所示。


图 13. 新一次的执行时间
图 13. 新一次的执行时间 

注意事项

由于脚本的执行受测试环境的影响,所以在实际执行中应该针对不同的环境建立不同的基准时间。此外,如果在某次测试过程中,发现某些脚本的执行时间与平均值有显著差异,可以留意一下是否存在潜在的性能问题。

本文的实验基于 RFT 实现,下载部分所提供的代码均在 RFT 8.0 下编译通过,但不保证在其它测试工具下的效果。另外本文提供的 Java Excel API 2.6.12 版本需要 JDK 1.6 的环境,在 1.5 的环境下若使用 Eclipse 编译会有“无法装入 Java 类”的错误提示。

总结

本文提出并采用 RFT 实现了一种基于时间的自动化测试监控方法。已有的 RFT 工程中只需要做一些微小的改动即可实现该方法。本方法有优点也有缺点。

本方法的优点有:

  • 当测试人员选定要执行的批量脚本的时候,即可知道大概需要多少时间完成,他 / 她就可以知道大概什么时间来查看最终的结果。
  • 当某一个脚本异常中断或者被堵塞,可能会导致单个脚本的实际执行时间和预期执行时间有差异,但不会影响对剩余脚本执行时间的预估。
  • 通过与基准时间的比较,有助于发现潜在的性能问题。
  • 在执行过程中,测试人员可以从远程的机器实时地监测剩余时间。

本方法也存在不足之处:

  • 预估时间是以以往的经验数据为基准,并非完全的根据当前测试用例的实际执行情况,当脚本执行情况出现异常的时候,往往预期的剩余时间和实际情况存在差异。
  • 如果脚本异常终止,重新启动时也需要重新启动监控。同时需要脚本可以读取之前已经成功执行的脚本个数,否则,将会出现基准时间和要执行的脚本不一致的情况。
  • 本方法不适合并发执行的批量脚本,例如:一批脚本会根据当前测试机的空闲情况分配到不同的测试机上并发执行,这种情况下本方法就不适用了。

本例虽然在 RFT 中实现,但是其原理也同样适用于其他的自动化测试工具。自动化测试过程的实时监控是一个复杂的课题。本文提供了其中的一种解决方案,我们希望能够抛砖引玉,使得读者可以更好地处理这方面的问题。

原文链接:http://www.ibm.com/developerworks/cn/rational/r-cn-rfttimebasedmonitoring/index.html

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/14780873/viewspace-670089/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/14780873/viewspace-670089/

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值