为了账号安全,请及时绑定邮箱和手机立即绑定

性能测试干货分享:JMeter如何使用Bean Shell进行参数化?

标签:
MySQL

在性能测试过程中,为了能够真实模拟用户请求,往往要将请求的报文进行参数化处理。JMeter配置元件与前置处理器都可以进行参数化,但都存在局限性。为了帮助用户更好地进行参数化,JMeter提供了BeanShell取样器。

性能测试干货分享:JMeter如何使用Bean Shell进行参数化?

BeanShell取样器支持BeanShell脚本语言,这是一种完全符合Java语法规范的脚本语言。下面就以一个样例来说明,如何使用BeanShell来进行参数化。

1.需求场景

有一个TCP服务,接收并处理地理位置上报的报文。报文由以下几部分组成:消息头+消息体+校验码。其中,除了消息体之外,其他部分可以是固定的,消息体包含地理位置的经纬度、速度消息和发送时间。经纬度是长度为8位的16进制字符串,速度消息也是8位的16进制字符串,可以固化,发送时间是时间戳。要求上报的位置消息频率是1秒,每次上报的位置需不同。

TCP服务接收到位置报文之后,进行业务处理,然后返回一个16进制的报文。

2.测试脚本准备

对于此测试需求,光使用JMeter内置的函数,是不能满足的,因此考虑使用Bean Shell处理,通过编写Java方法的方式进行参数化设置。

打开JMeter,按以下步骤进行操作。

(1)添加线程组

在测试计划上右键点击->添加->线程(用户)->线程组:

性能测试干货分享:JMeter如何使用Bean Shell进行参数化?

线程组设置如下:

性能测试干货分享:JMeter如何使用Bean Shell进行参数化?

线程组名称设为:BeanShell示例。这里设置100个线程,循环1次,也就是要发送100个请求,每个请求的报文都不相同。

(2)添加Bean Shell取样器

在线程组上右键->添加->取样器->Bean Shell取样器:

性能测试干货分享:JMeter如何使用Bean Shell进行参数化?

添加成功后如下图所示:

性能测试干货分享:JMeter如何使用Bean Shell进行参数化?

(3)编写Bean Shell脚本

用Java编写以下脚本:

package com.example.rabbitmq.rabbitmq;

import java.text.ParseException;

import java.text.SimpleDateFormat;

public class Baowen {

// 出发城市的经度

private static double Depart_City_longitude=110.330685;

// 出发城市的纬度

private static double Depart_City_latitude=20.035221;

// 抵达城市的经度

private static double Arrival_City_longitude=110.720005;

// 抵达城市的纬度

private static double Arrival_City_latitude=19.610221;

// 两个城市之间单程的位置点数

private static int count=5000;

private static String dateFormate=“yyMMddHHmmss”;

private static String baseTime=“200609153143”;

// 报文前缀

private static String beginMsg=“02004022018986042206198026706200010000000000000003”;

private static String midMsg=“000B00020111”;

// 报文后缀

private static String endMsg=“010400000000EE7E”;

// 经度上移动的步频

private static Double getLongitudeStep() {

return (Depart_City_longitude - Arrival_City_longitude) /count;

}

// 纬度上移动的步频

private static Double getlatitudeStep() {

return (Depart_City_latitude - Arrival_City_latitude) /count;

}

// 把整数转换为长度8位的16进制字符串

private static String integer2HexString(Integer number) {

String result=Integer.toHexString(number);

int len=result.length();

StringBuilder sb=new StringBuilder("");

// 不足8位时,前面补0

if(len < 8) {

for(int i=len; i < 8; i++) {

sb=sb.append(“0”);

}

sb.append(result);

}

return sb.toString();

}

public static String getLocationMsg(int num) {

double longitude, latitude;

// 如果位置点已经到达目的城市,则需返回,上传返程的位置点

if((Depart_City_longitude - num*getLongitudeStep()) >=Arrival_City_longitude) {

longitude=Arrival_City_longitude + (num%count) * getLongitudeStep();

latitude=Arrival_City_latitude + (num%count) * getlatitudeStep();

} else {

longitude=Depart_City_longitude - (num%count) * getLongitudeStep();

latitude=Depart_City_latitude - (num%count) * getlatitudeStep();

}

System.out.println("longitude: " + longitude);

System.out.println("latitude: " + latitude);

String strLongitude=integer2HexString(new Double(longitude*1000000).intValue());

String strLatitude=integer2HexString(new Double(latitude*1000000).intValue());

System.out.println("strLongitude: " + strLongitude);

System.out.println("strLatitude: " + strLatitude);

SimpleDateFormat sdf=new SimpleDateFormat(dateFormate);

long time=System.currentTimeMillis();

try {

time=sdf.parse(baseTime).getTime();

} catch (ParseException e) {

e.printStackTrace();

}

// 每次上报报文的时间,随着线程号每次递减1000毫秒,保证间隔1秒的频率发送报文

String strTime=sdf.format(time - num*1000);

System.out.println( strTime);

String msg=beginMsg + strLatitude + strLongitude + midMsg + strTime + endMsg;

return msg;

}

}

// 通过上下文获取JMeter正在运行的线程号

int threadNum=ctx.getThreadNum();

log("当前线程号: " + threadNum);

String msg=Baowen.getLocationMsg(threadNum);

log("报文: " + msg);

// 通过内置的vars对象,把报文放入变量容器中,变量的key为msg,供后面的脚本使用

vars.put(“msg”, msg);

说明:

1、对时间的处理:以基准时间为参考,每次上报报文的时间,随着线程号的递增,每次递减1000毫秒,这样可以保证间隔1秒的频率发送报文。

2、对位置的处理:设置往返的两个地点,每次上报一个位置,经纬度都按照指定的步频变化,当经纬度等于或超过终点时,又从终点开始返回,这样来模拟两个城市之间往返。

3、最后把结果放入JMeter的变量容器中,后续脚本只需以“${msg}”就可以引用该变量(如果获取不到,需要vars.get("msg "))。

(4)添加TCP取样器

在线程组上右键->添加->取样器->TCP取样器:

性能测试干货分享:JMeter如何使用Bean Shell进行参数化?

由于本次测试的是TCP服务,所以这样需要添加一个TCP取样器。古玩论坛TCP取样器配置如下:

性能测试干货分享:JMeter如何使用Bean Shell进行参数化?

TCPClient classname:填写TCP报文格式,有三类,这里选择org.apache.jmetertocol.tcp.sampler.BinaryTCPClientImpl,是常用的十六进制报文格式。

Re-use connection:复用TCP长连接请求。TCP长连接的时候需要勾选它。

EOL(行尾字节值):报文结束标志。因为报文是16进制的,报文的结束标志字符是7e ,7e的二进制是 0111 1110,对应的十进制是126。

(5)添加察看结果树

在线程组上右键->添加->监听器->察看结果树:

性能测试干货分享:JMeter如何使用Bean Shell进行参数化?

(6)添加聚合报告

在线程组上右键->添加->监听器->聚合报告:

性能测试干货分享:JMeter如何使用Bean Shell进行参数化?

3.测试结果

点击执行按钮,结果如下:

性能测试干货分享:JMeter如何使用Bean Shell进行参数化?

性能测试干货分享:JMeter如何使用Bean Shell进行参数化?

通过聚合报告可知,请求全部发送成功,并且得到正确的响应。通过察看结果树,对比不同的TCP取样器,可以看到请求报文的差异:

报文003:020040220189860422061980267062000100000000000000030131b5eb069383d8000B00020111200609153141010400000000EE7E

报文004:020040220189860422061980267062000100000000000000030131b59606938426000B00020111200609153140010400000000EE7E

4.Bean Shell的应用场景

以上介绍的是自定义函数场景下对Bean Shell的使用。事实上,Bean Shell还有其他的应用场景。

(1)引用外部Java文件

如果已经有了现成的Java文件,或者需要从外部Java文件中调用方法,那么可以使用Bean Shell引入Java文件,在脚本中使用。

比如:现有一个Java文件,名为MyJavaFile.java,在Bean Shell脚本中可以这样使用:

// 引入外部Java文件

source(“D:/script/MyJavaFile.java”)

// 调用Java文件中的方法

String result=new Baowen().getLocation();

// 保存变量

vars.put(“msg”, result);

在bean shel中通过source(“代码绝对路径”)的方式引入java,然后就和普通的Java类一样调用其方法就行。

(2)引用外部class文件

这种方式跟上一种类似,先用addClassPath(“class文件所在的目录”)引入 class文件,然后再用“import包名.类名“的方式导入类,接下来就可以调用class文件当的类和方法了:

// 引入外部class文件

addClassPath(“D:”)

// 导入包和类

Import MyPackeage.Baowen;

// 调用Java文件中的方法

String result=new Baowen().getLocation();

// 保存变量

vars.put(“msg”, result);

(3)引用外部Jar包

外部Jar包要先导入测试中,可以通过两种方式进行导入。其一,是在测试计划中,通过浏览按钮,将需要导入的jar包引入。

性能测试干货分享:JMeter如何使用Bean Shell进行参数化?

另外,也可以把Jar包放在JMeter安装目录|lib\ext下。

然后在Bean Shell中引用:

// 导入包和类

Import MyPackeage.Baowen;

// 调用Java文件中的方法

String result=new Baowen().getLocation();

// 保存变量

vars.put(“msg”, result);

Bean Shell是一个小型的、免费的、嵌入式的Java源代码解释器,具有对象脚本语言特性,能够动态地执行标准JAVA语法。并且,Bean Shell支持“松散的”或者动态地指定类型类型。能够在运行时做类型检查,而不需要先定义变量以及指定特定的变量类型来指向变量。

因为Bean Shell是用java写的,运行在同一个虚拟机的应用程序,因此可以方便地引用脚本中的对象,能够满足复杂的参数化需求。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消