内容


使用 Rational Performance Tester 检测运行时参数化问题

应用基于 Java 的自定义代码来模拟复杂工作负载

Comments

要充分测试性能,测试人员必须能够模拟两种类型的大型负载:

  • 大量(例如 5000 个)并发用户或活动用户
  • 高页面吞吐量(例如每秒 100 个页面)

对于大容量测试,很难准备测试数据,并在运行时将其提供给自动化工具。性能测试自动化工具可能遇到两种与运行时参数化或数据池有关的常见问题:

  • 工具无法准确记录特定故障类型的测试数据信息。没有自动化,这些工具就无法检测无效的测试数据或故障来源。
  • 工具无法轻松地从文件读取大量用户数据。高吞吐量可能带来负载生成问题,因为它会给负载生成器操作系统带来过量的 I/O。包含过量数据项(>65500)的 Excel 电子表格无法在运行时用于加载测试数据。

IBM® Rational® Performance Tester 包含自定义代码特性,该特性解决了这些问题。您可能很熟悉使用自定义代码自定义测试脚本来控制回放行为和调整报告机制。因为这个基于 Java™ 的自定义代码特性是一个独立的 Java 程序,所以您可以使用自定义编码功能来处理几乎所有自定义需求。

本文将介绍如何扩展 Rational Performance Tester 的功能,以便对报告测试数据故障的日志进行自定义,并使用自定义代码实现运行时参数化。

检测和记录无效或错误的测试数据

本文基于图 1 中所示的简单场景,其中一个用户登录到一个应用程序中,访问他或她的履历页面,然后注销。在测试期间,测试人员在运行时替换 username 的测试值(出于测试之目的,密码对所有用户都是相同的)。测试人员必须找到一种在运行时创建自定义日志的有效方式。日志必须包含测试期间使用的 username 值的总数,能够成功登录的用户名的详细信息。

图 1. 测试案例场景
本文中使用的场景的用例图

使用自定义代码传递参数

在运行时创建的自定义日志文件需要包含每个 username 值,以及在它登录成功或失败时触发的条件的信息。

第一步是添加自定义代码来将 username 值记录在一个文件中。此操作在测试脚本中执行,如图 2 所示。

图 2. 测试脚本
Login_Testcase 目录中的页面列表

Home Page 的测试数据包含 usernamepassword 的详细信息,如图 3 所示。

图 3. Home Page 的测试数据
主页的用户名和密码测试数据
主页的用户名和密码测试数据

要创建一个自定义日志文件,可以执行以下步骤:

  1. 对于 username,为 username 变量指定一个数据池,在本例中为 User_datapool,如图 4 所示。
图 4. “Substituted with” 列中的数据池名称
将 username 值替换为 User_Datapool
将 username 值替换为 User_Datapool
  1. 要捕获用于执行登录事务的 username 值,可以使用以下步骤,插入一段自定义代码,并将该数据池值作为参数传递给该代码,如图 5 所示。
    1. 选择加粗的主要请求下方的辅助请求。
    2. 单击 Insert
    3. 选择 Custom Code
图 5. 插入自定义代码来捕获 username 值
选择 request,单击 Insert,然后选择 Custom Code
选择 request,单击 Insert,然后选择 Custom Code
  1. 使用以下步骤将参数传递给自定义代码,如图 6 所示。
    1. 对于 Class name,键入 customcode.Username_Logger
    2. 单击 Add
    3. 选择 Username variable of User_Datapool datapool
    4. 单击 Select 传递该参数。
图 6. 将参数传递给自定义代码
选择要接收参数的自定义代码
选择要接收参数的自定义代码
  1. 单击 Generate code 生成默认的自定义代码模板,如图 7 所示。
图 7. 单击 Generate code
该屏幕截图显示了 Generate Code 按钮
该屏幕截图显示了 Generate Code 按钮
  1. 执行以下步骤来确定要捕获哪些 username 值:成功登录的用户名还是未成功登录的用户名。创建一个 IF 条件,使自定义代码能够捕获您想要记录的 username 值。例如,如果关键词 Welcome 表示用户成功登录,那么可以添加此关键词作为要搜索的内容,以响应登录请求。捕获满足此条件的 username 值。
    1. 选择主要 URL 下出现的辅助请求,如图 8 所示。
    2. 单击 Insert
    3. 选择 Condition (If)。如果获得提示,则单击 Yes
图 8. 添加 If 条件来评估成功事务
if 条件
if 条件
  1. IF 条件可确保自定义代码只记录满足这个 IF 条件的 username 值。要定义该条件,可以对比两个操作数:Welcome 关键词和对登录请求的响应,我们要搜索出现 Welcome 关键词的信息。使用以下步骤创建一个引用并将它添加到 IF 条件中。
    1. 选择加粗的主要请求的响应。
    2. 右键单击响应内容,如图 9 所示。
    3. 选择 Create Field Reference,这会创建完整响应内容的引用。
      图 9. Create Field Reference
      登录响应和 Create Field Reference
      登录响应和 Create Field Reference
    4. 将该引用命名为 Content:Login_Response。单击 OK,如图 10 所示。
      图 10. 为字段引用命名
      Edit Reference Name 对话框
      Edit Reference Name 对话框
  1. 执行以下步骤,将日志文件名和路径定义为一个全局变量,如图 11 所示:
    1. 选择测试脚本中的 Test Variables 条目。
    2. 单击 Add
    3. 选择 Variable Declaration
      图 11. 添加文件名称和路径作为一个全局变量
      选择 Test Variables,然后选择 Add Variable Declaration
      选择 Test Variables,然后选择 Add Variable Declaration
    4. 键入 FileName 作为 Variable Name
      图 12. 变量名称
      Variable Name 字段显示为 FileName
      Variable Name 字段显示为 FileName
    5. 将此变量的值初始化为您的日志的文件名,如图 13 所示。在本例中,文件名为 C:\\Valid_Data_Log.txt。(请注意,我们使用了两个反斜杠来避免特殊字符 \。在 Unix 操作系统上指定文件名时,不需要额外的反斜杠字符,因为 Unix 操作系统中使用的文件分隔符为正斜杠 (/))。
图 13. 初始化该变量
Text 字段中的 C:\\Valid_Data_Log.txt
Text 字段中的 C:\\Valid_Data_Log.txt
  1. 返回到脚本中的自定义代码,将此变量添加为第二个参数,如图 14 所示。
图 14. 将文件名作为参数添加到自定义代码中
指定 FileName 变量
指定 FileName 变量
  1. 将清单 1 中的代码插入到 Username_Logger.java 文件中。
清单 1. 记录 username 值的自定义代码
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
BufferedWriter out=null;
FileWriter fstream;
   try {
      fstream = new FileWriter(args[1], true); //true signifies data append instead of overwrite
      out = new BufferedWriter(fstream);
      out.write(System.getProperty("line.separator")); //inserts a new line in the file
      out.write(args[0]); // writing the username value into the file
   } 
   catch (IOException e) {
      e.printStackTrace();
   }
   finally
   {
      if(out != null) {
        try {
            out.close();
         } catch (IOException e) {
            e.printStackTrace();
         }
      }
}

现在该脚本已准备好将所有有效的 username 值都记录在 C:\ 目录下的日志文件 Valid_Data_Log.txt 中。

此方法的扩展

可将此方法用于其他用途。例如,可在 IF 条件中选择 Negate the operator (NOT (op)) 选项来记录无效或错误的 username 值。通过更改 IF 条件,可以控制要记录的数据。

还可以依据您的具体要求来自定义此方法,从而验证其他测试数据和测试其他条件。

通过自定义代码来启用运行时参数化

您可以使用 Java 自定义代码在运行时从外部文件传递数据池值。此方法解决了许多已有的问题:

  • 数据池在代理之间的不均衡分布,以及跨代理共享相同数据的困难性(在共享和分段模式下)。
  • 无法使用控制哪些数据需要放在哪些代理机器上的方法,自定义负载模拟。
  • Excel 电子表格处理大量数据的问题
  • 通过传统的数据池方法从高容量负载传来的过量 I/O。

借助自定义代码,可以将上一个场景中使用的 username 的值替换为一个外部文件中的值,而不使用 Rational Performance Tester 中包含的传统的数据池特性。

使用清单 2 中的代码实现此方法。这段自定义代码从一个文件读取值。您可以自定义此代码来满足您的需求。

清单 2. 自定义代码来手动执行运行时参数化
int total_users_per_agent=<<xxxx>>;
String datapool_var=null;
   
   int current_user = Integer.parseInt(args[0]);
   //args[0] is the Username datapool that will be passed to this    custom   code
               
   try {
   ArrayList<String> datapool_array = new ArrayList<String>();
   Scanner s = new Scanner(new File("C:\\Datapool.csv"));

   while(s.hasNext())
   {
      datapool_array.add(s.next());
   }
   s.close();
               
   //applying mod function here...
   int user_cnt= current_user-   (total_users_per_agent*((current_user/total_users_per_agent)));
               
   String[] desired_column_value_datapool =    datapool_array.get(user_cnt).split(",");

   datapool_var = desired_column_value_datapool[<<index_of_column>>];
   
   } catch (FileNotFoundException e) {
      e.printStackTrace();
   }
   return datapool_var;
   //datapool_var is the desired row-column value of the datapool

变量 total_users_per_agent 表示在一个代理机器上运行包含此自定义代码的测试脚本的虚拟用户数量。

备注:在此上下文中,代理机器是一个典型的机器,而不是 Rational Performance Tester 负载驱动程序代理的一个实例 (JVM)。

变量 total_users_per_agentcurrent_user(来自 username 数据池)用于计算数据池文件中的行索引。此行的内容存储在 datapool_array 字符串变量数组中。Java 拆分函数用于通过一个逗号分隔符来拆分行内容,从而得到各个值。此自定义代码要求数据池为 CSV 格式。

创建自定义代码和传递参数 的分步方法可用于实现自定义代码,从而启用运行时参数化。

要知道的问题

在写入文件中的数据很少时,可以使用自定义代码日志记录方法。不要使用此方法记录请求的所有响应,因为此操作会导致大量 I/O 操作,而磁盘 I/O 延迟和很长的 I/O 进程队列会导致很高的 CPU 等待时间,进而导致性能降低。

这些操作或相关问题(比如使用大量自定义代码导致的更大的内存占用或高内存消耗)会导致性能降低,导致负载生成能力降低。负载生成硬件上的高 CPU 使用率与性能测试工具所报告的糟糕的响应时间有直接的关系,因为高 CPU 使用率会导致测试工具有时处于挂起状态。因为测试工具报告的响应时间中添加了它自己在接收响应过程中的延迟,所以性能度量值是失真的。

监视您的负载生成硬件的利用率。在运行性能测试期间,特别监视工作台和代理机器的处理器利用率。在模拟系统中的大量并发用户期间监视 Java 进程的内存使用情况,这很有帮助。TCP/IP 套接字的利用率也会影响服务器上生成的大量请求所导致的负载生成性能。必须监视和检查磁盘 I/O 利用率,以检测测试计划中配置的过量的日志记录或日志记录水平所导致的磁盘延迟。

确保 CPU 利用率数值不会超过某个阈值限制。不同类型的应用程序测试需要为负载生成硬件利用率设定不同的阈值。在大部分情况下,不要允许负载生成环境的利用率超过 70%。将 CPU、内存、磁盘、网络或 TCP/IP 套接字的阈值设置为 70%。

努力构建自定义代码,将负载生成期间的自动化工具性能保持在可接受的限制内。


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Rational
ArticleID=983135
ArticleTitle=使用 Rational Performance Tester 检测运行时参数化问题
publish-date=09112014