科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件对Rational Performance Tester的改进

对Rational Performance Tester的改进

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

本文从数据池的角度出发,结合实际环境中遇到的一些问题,来扩展 RPT 的数据驱动能力。

作者:聂健 来源:论坛整理 2007年11月17日

关键字: Rational Performance

  • 评论
  • 分享微博
  • 分享邮件
 Rational  Performance Teser(RPT)是专门针对 B/S架构和专用系统(SAP,Citrix 等)进行压力测试的工具。RPT 基于开放的 TPTP 平台和 Java 语言其实对我们的测试提供了很大的扩展性。本文从数据池的角度出发,结合实际环境中遇到的一些问题,来扩展 RPT 的数据驱动能力。

  前言

  在性能测试中,我们往往遇到这样的一些问题,比如需要通过不同的用户进行登录操作,或者需要动态的输入数据,在测试工具中往往我们是通过数据池来进行完成的。比较全面的数据池的设计往往会考虑用户数据的来源,比如文件,数据库等多种形式,但其实如果采用直接映射数据库中的某些列来进行实现,虽然在操作上会省下很多数据加工的时间,但在实际运行过场中会有诸多缺点,主要体现在每个用户每次获取数据时就需要消耗大量的时间,因为往往数据库在远程的服务器上而非本地,如果频繁的交互会使真正需要了解的响应时间大打折扣。出于测试尽可能反映真实的应用响应时间的考虑,Rational Performance Tester 采用了文件的方式来进行数据的导入。

  Rational Performance Tester 内置的 DataPool 的实现机制

  Rational Performance Tester 内置的数据池采用了 TPTP 的前身 Hyades 测试框架的实现方式,也就是通过 EMF 进行实现。其设计图为:

  图 1: 设计图

  设计图

  其中比较主要的几个概念是:

  •   Variable:主要指一个列,通常包含一个名字和建议的类型
  •   Record:行,包含多列的数据
  •   Cell:数据块,对应的是某行某列
  •   EquivalenceClass:等价类,数据池中记录的逻辑组合
  •   Datapool:数据池

  往往我们在通过 RPT 的界面建立数据池或者从 CSV 文件导入数据池时,会发现在我们的 workspaces 项目的根目录下中生成了一个 .datapool 的文件,把文件通过 winrar 解开,可以看到是一个 xmi 文件,格式如下:

<?xml version="1.0" encoding="UTF-8"?>
<Common_Datapool:DPLDatapool xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" 
    xmlns:Common_Datapool="http://www.eclipse.org/hyades/models/common/datapool.xmi" 
    id="E123A884D00625FC60097F300AD111DC" name="aa">
    <equivalenceClasses id="E123A884D00625FC6021E9300AD111DC" name="String">
        <records>
            <cells value="&lt;Literal>eric&lt;/Literal>" 
                variable= "E123A884D00625FC600C8C700AD111DC "/>
            <cells value="&lt;Literal>ericnie&lt;/Literal>" 
                variable="E123A884D00625FC602062900AD111DC"/>
        </records>
        <records>
            <cells value="&lt;Literal>eric1&lt;/Literal>" 
                variable="E123A884D00625FC600C8C700AD111DC"/>
            <cells value="&lt;Literal>ericnie1&lt;/Literal>" 
                variable="E123A884D00625FC602062900AD111DC"/>
        </records>
        <records>
            <cells value="&lt;Literal>eric2&lt;/Literal>" 
                variable="E123A884D00625FC600C8C700AD111DC"/>
            <cells value="&lt;Literal>ericnie2&lt;/Literal>" 
                variable="E123A884D00625FC602062900AD111DC"/>
        </records>
        <records>
            <cells variable="E123A884D00625FC600C8C700AD111DC"/>
            <cells variable="E123A884D00625FC602062900AD111DC"/>
        </records>
    </equivalenceClasses>
    <datapoolSpec id="E123A884D00625FC60097F310AD111DC">
        <variables id="E123A884D00625FC600C8C700AD111DC" name="name" type="String”/>
        <variables id="E123A884D00625FC602062900AD111DC" name="password" 
   type="String”/>
    </datapoolSpec>
</Common_Datapool:DPLDatapool>

  这个 xmi 文件实际就是我们数据池实例 aa 的序列化后的形式,系统在实际调用时会将其反序列化同时将相关的数据 load 到内存中去。在 Rational Performance Tester 中打开这个 xmi 文件,可以清晰的看到它的层次结构,同时可以对它进行修改。

  图 2: 层次结构

  层次结构

  采用 EMF 设计的一个很直接的好处是,系统可以自动的根据模型生成代码,同时实现了 UML 模型,XML Schema, 注释过的 Java 接口表现模型的统一。但在实际环境中,采用 Rational Performance Tester 内置的 DataPool 还是有很多不太方便的地方,比如:

  1) 要经常对文件中的数据进行变化,然后再重新测试时

  很多时候测试完后,数据就暂时没用了,因为状态已经更新了,为此需要对测试数据进行替换,但在 RPT 目前的这种序列化反序列化的机制中,要实现这一点并不容易,所以体现在界面中的操作实际上是比较繁琐的,表现为:

  •   要重新加入一个新的 Pool
  •   需要对原来的变量去掉关联
  •   关联新的 Pool 中的变量

  如果你的变量比较多,还是非常繁琐的,而且不是一种最好的解决办法。

  2) 当测试数据很大,比如文件大概 50M 或更多时

  这时候内置的机制会产生一些问题,装载数据时比较慢。这在早期的 6.x 版本中经常遇到,但现在 70 有没有这个问题倒是需要看看底层机制是否有更改。

  正因为上面的问题,同时还频繁在实际的测试过程中遇到,因此找到一种更好的替代方案对于实际的项目更加迫切,好在 RPT 建立在 TPTP 的架构上,也就意味着建立在纯粹的 Java 的实现机制下,因此提供了让人很方便的插入 Java 代码的方式,使得很多的扩展和增强成为可能。下面我们就来谈谈如何解决这两个问题。

  Rational Performance Tester DataPool 的扩展

  为了扩展 DataPool 我们决定对这个环节进行重新的设计,原则如下:

  • 考虑对真实测试性能影响最小的原则,我们把所有的数据都放在文本文件中,变量间通过逗号来进行分隔。
  • 考虑到内存的开销,同时不需要把所有的数据都读入到 JVM 中进行处理的原则,我们通过了一个 ArrayList 来存放一次读入的数据,这些数据会分配给每个 Virtual User, 同时如果读到最后行时,会重新调用方法进行对 ArrayList 中数据的刷新。
  • 通过变量来控制一次读入的文件行数。
  • 一开始的时候考虑把通过二维数组来进行变量的读取,但后来在调试过程中发现,很难解决不同的变量读取同一行的问题,往往在一次读完后就指针就指到下一行去了,而因 RPT 本身并不是全部的 Java 脚本,而是 Java 脚本和页面表示的混合,Java 脚本和页面间其实是通过变量来进行沟通的,这造成的一个很现实的问题是,如果我们仅仅获取一个变量而不是每行的时候,无法控制在哪条语句后移动 cursor。后来就改变了设计,采用了一起获取一行的方式,对于变量的返回通过对行的解析得到。

  改变的设计

  • 通过 PoolLoad 定义静态的数据池类
  • 通过 getLine 返回当前 VU 对应的行
  • 通过 getVar 解析返回行,从而返回需要的变量

  经过设计的类图如下:

  图 4: 经过设计的类图

  经过设计的类图

  关键代码的解释:

  RPTDataPool.java:主要用于将记录以分页的形式从文件中读入到 ArrayList 中

  首先定义需要的变量:

Private String DataPoolFileName;// 定义数据池文件存放的位置,运行时会由 PoolLoad.java 装入
        private ArrayList DataPool;// 存放每次从数据池中读出的记录
        private int cursor = 0;// 当前记录的光标
        static private int pageno = 1;// 根据每页的大小 (PageSize), 目前光标停在哪页
        private int pagesize = 500;// 每次 load 进 DataPool 的记录数量

  构造函数 RPTDataPool:

  调用 fillPageByLine 方法,把文件的第一个页面存入到变量 DataPool 中来。

public RPTDataPool(String fileName ) {
   
    ……
   
    fillPageByLine( DataPoolFileName, DataPool, 1);

  fillPageByLine: 每次到了页面的记录末尾,都会被调用,从而把相关的记录读到 DataPool 中来。

private boolean fillPageByLine(String fileName, ArrayList FileLines, int Pageno) {
    // 通过 ReadLine 读文件 ;
    while (line !=null) {
    // 当前行数在关注的页面中, pageno 通过参数传入
    if ((lineno>=pagesize*(Pageno-1))&&(lineno<pagesize*Pageno)) {
        FileLines.add(line);// 把当前记录加入 ArrayList
        line=br.readLine();// 记录下移
        lineno++;// 行数增加
    } else if (lineno<pagesize*(Pageno-1)) {// 当前行数还没到关注的页面
        line=br.readLine();// 记录下移
        lineno++;// 行数增加
    } else if (lineno >= pagesize*(Pageno)) {// 当前行数超过关注的页面
        break;// 退出
    }
}

  PoolLoad.java: 传入文件位置,初始化 RPTDataPool

  文件只包括一行,就是调用 RPTDataPool 的构造函数:

  static RPTDataPool pool1 = new RPTDataPool("c:\\pool1.txt");

  getLine.java: 每个 RPT 的 Test 中,在需要数据池前需要插入的代码,用于把当前用户对应的数据池记录通过一行返回给 Test

public String exec(ITestExecutionServices tes, String[] args) {
    // 调用 PoolLoad 中初始化的 pool1 的 getDataPoolItemLine 的方法返回当前行然后把 line 返回给 Test
    String line = PoolLoad.pool1.getaDataPoolItemLine();
    return line;
}


  getName.java: 从返回的行中取出需要的字段 ,每个变量对应着一个 get 方法,比如 getName, getPassword 等 。
public String exec(ITestExecutionServices tes, String[] args) {
    // 从参数中读出记录行到 line
    StringTokenizer st = new StringTokenizer(line,",");// 转换成 StringTokenizer
    while (st.hasMoreTokens()) {
    if (i == index) { // 匹配需要的字段
        name = st.nextToken(); // 把相应的字段赋值
        break;
    }
    i++;
}

  Rational Performance Tester 对编写脚本的调试

  如何调试客户化的 RPT 脚本,因脚本在后端运行时,无法看到任何的控制台信息,运行完也无从发现,因为 log 信息也被序列化成 xmi 了,因此采用 System.out.println 基本是没有办法了,这里提供了两种方式:

  通过将调试信息写入文件的方式 。

  首先定义变量: String mess = “begin”;

  然后在需要输出的位置,把信息附在 mess 中, 比如: mess = mess +line + "*******\r\n";

  在方法调用完后,把 mess 信息输出到文件,如下:

try {
FileWriter outFile = new FileWriter("C:\\response1.txt");
outFile.write(mess);
outFile.close();
} catch (Exception e) {
}

  最后直接打开文件,查看相关的内容 。

  如果是在 RPT Test 中的代码,可以采用 TPTP 的 Log, 将相关信息输出到执行日志中 。

  首先 import IVirtualUserInfo, 主要是为了得到当前的用户 id。

  然后调用 ITestExecutionServices 的 getTestLogManager 的 reportMessage 方法,把需要的信息记录到 TPTP Log 中 。 Tes.getTestLogManager().reportMessage(

  "name =" + Integer.toString(vui.getUID()) + "==" + name);

  调试方式的比较:

  在第一种方式下,能直接以文件的方式一目了然所有的输出,但无法看到那个虚拟用户的 id 等信息,这是传统的,大家比较适应的方式。

  通过 TPTP Log 的方式,查看起来比较麻烦,需要在执行日志中展开来看每个节点的返回,效率比较低,如果要象第一种方式下以文件的方式,需要用 winrar 解开 .execute 文件 ( 执行日志 ), 然后会看到 EMF 模型实例的序列化的 xmi 文件,然后通过 ultraedit 打开了就可以看到了。

  总结

  Rational Performance Tester 构建于 Eclipse 的 TPTP 的测试框架 ,它是 Eclipse 的一类项目 (Top Projects)之一,目前仍然在不断的发展,基于 TPTP 的框架,一方面能很方便的采用框架上已经提供的功能,比如 DataPool,TPTP Log 等,另外,因为 TPTP 本身基于 Java 架构,因此完全可以通过 Java 底层的提供的强大的 API 来客户化代码满足各种不同环境下的不同需求,本文就是对数据池进行改造的一个例子。大家在实际的使用过程中也可以采用各种新的 Eclipse 的技术,比如 EMF,BIRT 来对 RPT 进行各种扩展。开放的架构,灵活的扩展方式和丰富的接口,这也就是我们认为的开放的力量吧。

查看本文来源

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章