• 11
  • 12
分享
  • JMeter之使用Bean Shell进行参数化——软件测试圈
  • 曼倩诙谐 2021-04-28 10:04:49 字数 6025 阅读 2370 收藏 12

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

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

  1.需求场景

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

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

  2.测试脚本准备

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

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

  (1)添加线程组

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

1-1.png

  线程组设置如下:

1-2.png

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

  (2)添加Bean Shell取样器

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

1-3.png

  添加成功后如下图所示:

1-4.png

  (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.info("当前线程号: " + threadNum);
String msg = Baowen.getLocationMsg(threadNum);
log.info("报文: " + msg);
// 通过内置的vars对象,把报文放入变量容器中,变量的key为msg,供后面的脚本使用
vars.put("msg", msg);

   

  说明:

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

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

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

  (4)添加TCP取样器

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

1-5.png

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

1-6.png

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

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

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

  (5)添加察看结果树

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

1-7.png

  (6)添加聚合报告

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

1-8.png

  3.测试结果

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

1-9.png

1-10.png

  通过聚合报告可知,请求全部发送成功,并且得到正确的响应。通过察看结果树,对比不同的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包引入。

1-11.png

  另外,也可以把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写的,运行在同一个虚拟机的应用程序,因此可以方便地引用脚本中的对象,能够满足复杂的参数化需求。


作者:叶大师   

来源:51Testing软件测试网原创

  • 【留下美好印记】
    赞赏支持
登录 后发表评论
+ 关注

热门文章

    最新讲堂

      • 推荐阅读
      • 换一换
          •   据来自亚洲的未经证实的报道称,苹果公司在多次尝试完善自研 5G 调制解调器芯片但未成功后,将停止这一工作。据 Naver 博客上的新闻聚合账户“yeux1122”运营商透露,与苹果 5G 调制解调器部门相关的供应链消息人士称,该公司开发自己的调制解调器的尝试迄今为止已经失败,苹果正在结束其 5G 调制解调器业务,该项目长达数年的投资也随之泡汤。  另外,名为@Tech_Reve 的泄密者今天表示,他们从日本供应链来源听到了类似的报告。  现在判断最新报道是否属实还为时过早,但根据《华尔街日报》9 月份的报道,苹果开发自己的调制解调器芯片的尝试受到了一些问题的阻碍,包括不切实际的目标、对所涉...
            0 0 565
            分享
          •   “测试自动化测试工程师可以将你从充满代码的世界中拯救出来。”     企业完全同意这一说法,这就是您在自动化测试行业中看到大量就业机会的原因。我在Quora上收到了很多与自动化测试中的职业选择相关的答案请求,以及人们如何在有或没有手动测试经验的情况下适应自动化测试。  在这里,我将详细解释成为测试自动化工程师的七个最重要的步骤。因此,所有希望将职业转向自动化测试的人都要注意所有这些。  1. 不要忽视手动测试  虽然我了解公司正在转向无代码自动化测试工具,达到专家级别并跟上行业自动化测试工程师的竞争,但最初要关注手动测试概念非常重要。  首先,我想强调使用手动和自动测试的事实。有...
            12 14 1944
            分享
          • 前言在一线大厂,没有测试这个岗位,只有测开这个岗位即使是做业务测试,那么你的title也是测开所以想聊一聊测开的看法但不代表这是正确的看法,仅供参考还没来阿里之前,我对测开的看法一直以为专职做自动化测试和性能测试是测试这条路的最终归宿测试开发,只是大厂才可能存在的角色测试平台,少部分公司才会用到的东西,肯定不会成为主流的啦况且测试平台要会前端还得会后端,你都这么全栈为什么不做开发呢做 UI 自动化、接口自动化直接写 python 脚本不就好了嘛,做性能测试用 Jmeter 就好了嘛多数人眼中的测试开发开发一个测试平台,就要包揽前后端至...
            0 0 806
            分享
          • 读者提问:测试报告怎么写?阿常回答:测试报告通常包含这四要素:1、项目背景;2、参考资料;3、计划执行列表;4、测试结果。一、项目背景项目背景主要包含以下 4 点:1、测试产品名称(XX平台);2、测试周期(5.1~5.5);3、主要测试项目及具体内容(测试XX平台的功能是否正常实现、易用性是否满足用户需求);4、测试人员(测试员XX)。二、参考资料参考资料主要包含以下 4 点:1、测试计划(文档链接);2、需求规格说明书(文档链接);3、测试用例(文档链接);4、缺陷记录(jira链接)。三、计划执行列表计划执行列表主要包含以下 3 点:1、计划内容(功能测试、界面测试、易用性测试);2、执...
            0 0 1683
            分享
          • 1、引言关于接口测试,这针对大部分的测试工程师来说,都是必备的技能,而且,关于接口测试, 测试工程师从初探到成长的必经之路: 接口测试理解,→接口测试方法学习→ 单接口测试工具学习→接口自动化平台/工具学习→接口自动化脚本设计/编写→ 接口自动化框架设计→接口自动化平台设计/编码。按照这个流程, 你可以对照,你现在的接口测试等级,以及,你希望需要提升的方向。而今天分享的内容,是接口自动化框架的设计。由于接口测试方法, 接口测试工具的学习,都很简单, 所以,我也不做过多的赘述,我们把更多的精力,投入到需要提升的技能上。由于自动化框架的设计,需要根据项目来进行, 这里,我就以某...
            1 0 2643
            分享
      • 51testing软件测试圈微信