这个 xmi 文件实际就是我们数据池实例 aa 的序列化后的形式,系统在实际调用时会将其反序列化同时将相关的数据 load 到内存中去。在 Rational Performance Tester 中打开这个 xmi 文件,可以清晰的看到它的层次结构,同时可以对它进行修改。
图 2: 层次结构
采用 EMF 设计的一个很直接的好处是,系统可以自动的根据模型生成代码,同时实现了 UML 模型,XML Schema, 注释过的 Java 接口表现模型的统一。但在实际环境中,采用 Rational Performance Tester 内置的 DataPool 还是有很多不太方便的地方,比如:
要经常对文件中的数据进行变化,然后再重新测试时
很多时候测试完后,数据就暂时没用了,因为状态已经更新了,为此需要对测试数据进行替换,但在 RPT 目前的这种序列化反序列化的机制中,要实现这一点并不容易,所以体现在界面中的操作实际上是比较繁琐的,表现为:
要重新加入一个新的 Pool
需要对原来的变量去掉关联
关联新的 Pool 中的变量
如果你的变量比较多,还是非常繁琐的,而且不是一种最好的解决办法。
当测试数据很大,比如文件大概 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;// 退出 } } |