JMeter之BeanShell内置方法的使用

前言

本文是自己在日常使用过程中整理前辈们的知识,以及自己日常使用整理输出的结果,由于汇集了过多的文章、时间太长,无法一一列举曾经引用过哪些前辈了,实属抱歉。也限于个人水平有限,若有哪些写得不对的也欢迎指正。

本文主要介绍beanshell中的常用方法类以及使用案例。

友情提示:对于初学者,建议先捋清楚各个原件的执行顺序和作用域,还需要一点点Java基础。

BeanShell简介

  • 什么是BeanShell 官网 官方文档
    BeanShell是由java编写的,是一个轻量级的脚本语言,也相当于一个小巧免费的JAVA源码解释器,支持对象式的脚本语言特性,亦可嵌入到JAVA源代码中,能动态执行JAVA源代码并为其扩展了脚本语言的一些特性。
    简单的理解:beanshell就是一个能写java代码的
  • JMeter中与BeanShell的关系
    首先,JMeter也是由java编写的,而java运行时需要先编译,然后才可以运行;而BeanShell是一款解释器,直接可能运行源代码;
    所以,两者其实没有必然的联系,只不过是把beanshell嵌入到jmeter这个工具里面,然后通过jmeter定义的方法与beanshell进行交互;
  • 我们可以通过BeanShell做什么?
    • 读写请求、响应相关的信息(包括请求头、请求信息、响应头、响应码、响应体等)
    • 执行Java代码实现一定逻辑计算(请求加密、复杂的断言方式)

BeanShell元件所支持的变量、方法

为什么要说这个?因为不同的Beanshell 支持的变量不一样,直接使用会报错。如下图,可以通过元件知道支持什么变量。如图,可以根据远见的说明知道支持什么变量。


image-20220504165831908.png
  • BeanShell 取样器
    SampleResult、ResponseCode、ResponseMessage、IsSuccess、Label、FileName、ctx、vars、props、log
  • BeanShell 预处理程序
    ctx、vars、props、prev、sampler、log
  • 后置处理器:BeanShell PostProcessor
    ctx、vars、props,prev、log
  • BeanShell断言
    Read/Write: Failure、FailureMessage、SampleResult、vars、props、log
    ReadOnly: ResponseData、ResponseCode、ResponseMessage、ResponseHeaders、RequestHeaders、SampleLabel、SamplerData、ctx
  • BeanShell 定时器
    ctx、vars、props、log、prev
  • BeanShell 监听器
    ctx、vars、props

方法类适用的元件:

方法名 适用元件 说明
SampleResult BeanShell 取样器、BeanShell断言 需要import对象
ResponseCode BeanShell 取样器、BeanShell断言
ResponseMessage BeanShell 取样器、BeanShell断言
IsSuccess BeanShell 取样器
Label BeanShell 取样器
FileName BeanShell 取样器
ctx 所有元件
vars 所有元件
props 所有元件
log 除了监听器
prev BeanShell 预处理程序、后置处理器、定时器
sampler BeanShell 预处理程序
Failure BeanShell断言
FailureMessage BeanShell断言
ResponseData BeanShell断言
ResponseHeaders BeanShell断言
RequestHeaders BeanShell断言
SampleLabel BeanShell断言
SamplerData BeanShell断言

Beanshell的内置方法

beanshell常用API - 链接

每个方法里有说明对应的API,适用元件、适用例子,其中适用例子都是自己调试过的,可以直接复制粘贴使用。

log

JavaDoc
适用元件:除了监听器,其他元件都可使用。
log表示org.apache.log.Logger类,日志信息写入到jmeter.log文件。

  • log.info("响应状态码" + ResponseCode);
  • log.debu("调试信息");
  • log.warn("警告信息");
  • log.error("出错信息");
log.info("这里的信息会保存在jmeter.log文件中,并打印显示在jmeter的实时运行日志");

System.out.println("这里的信息会输出到jmeter的控制台(黑框里)");

日志显示位置:


image-20220504170620220.png

vars

JavaDoc
适用元件:所有元件
vars是于操作Jmeter变量,它是org.apache.jmeter.threads.JMeterVariables类的实例,提供对当前变量的读写。
所有的JMeter变量都是java字符串,如果需要把一些变量存放到一个JMeter变量中,需要先把它转换成字符串。
常用方法:

  • vars.get(String key); 从jmeter中获得变量值,如:vars.get("key"); 注意,需要用双引号,不能这样vars.get("${key}");

  • vars.put(String key,String value); 数据存到jmeter变量中,如vars.put("key","123456"); //变量名需要用双引号

  • vars.putObject("SAVED_ARRAY",[]); 赋值一个对象

  • vars.getObject(String key); 获取一个对象

    读取object,

    • 使用场景:读取JDBC request里的result variable names
    • 如:vars.getObject("sql_order_ids").get(2).get("id"));

注意:vars接收的值必须是字符串类型, 若传递其他类型,包括null,都会报错;如果想使用数字,数字等类型,方法是做类型转换;例如:

vars.put("key1", "" + 1);
vars.put("key2", (String)1);
vars.put("key3", [2, 3, 4].toString());
vars.put("key4", (String)[1,2]);
vars.put("key4", "" + [2, 3, 4]);
vars.put("key5", "" + true);
vars.put("key6", true.toString());


//列表字符串转为列表
String EsIdString = "13073895,  13082623,  16731457,  23075394,  20659718,  13082429,  13082482,  16731621,  16731576";
String[] ESsplist = EsIdString.split(",  ");
List EsIdList = Arrays.asList(ESsplist);
int EsIdLen=EsIdList.size();

vars.putObject("EsIdList",EsIdList);
vars.put("EsIdLen",""+EsIdLen);

props

适用元件:所有元件

作用:读写jmeter属性。注,只会在内存里创建、更新,不会在本地文件中创建、更新

props与vars对比差异

1、props是java.util.Properties的实例,与vars作用大致相同,区别的是 vars 是对变量进行读写操作, 而 props 主要是对属性进行读写操作。ps:侠义的属性指的是jmeter.properties、user.properties、jmeter.properties文件里的变量。
2、vars 只能在当前线程组内使用,props 可以跨线程组使用 ,因为属性可以跨线程组但是变量不行;
3、vars 只能保存 String 或者 Object,props 继承了 Hashtable 的类,所以拥有与 vars 类似的 get 和 put 方法,另外还继承了 Hashtable 的其他方法 ;

//判断某项属性是否存在,返回布尔值
props.containsKey("PROPERTY_NAME") 

//判断某项值是否存在,返回布尔值
props.contains("PROPERTY_VALUE")

//删除某个值
props.remove("PROPERTY_NAME")

//所有属性以字符串形式表示
props.toString()

常用方法

  • props.get(String) 可以获取Jmeter中已经生成的属性(静态变量);
    • 如:props.get("START.HMS"); 注:START.HMS为属性名,在文件jmeter.properties中定义;
    • 结合:测试计划 > 非测试原件 > 属性显示,查看当前jmeter环境存在的属性变量;
  • props.put(String,String) 可以创建和更新JMeter属性。
    • 如:props.put("PROP1","1234");
  • 使用__P() 调用属性值,如:${__P(PROP1,)}获取全局属性的值。

ctx

JavaDoc
适用元件:所有元件
ctx是JMeter内置变量中最强大的变量。它代表org.apache.jmeter.threads.JMeterContext类,实际就是JMeter本身,它提供对采样器、执行结果、变量/属性等的读写。

  • ctx 变量是JMeter JSR223功能最强大的内置变量之一,通过它可以轻松的访问当前线程的上下文;
  • 在 JMeter 内部,ctx 映射为 org.apache.jmeter.threads 的 JMeterContext 类;
  • 由于JMeterContext 不具有线程安全性,故仅适用于在单线程中使用;

常用方法:

  • ctx.getVariables("变量名"):获取变量值(同vars.get()),空时,获取当前线程所有变量??
  • ctx.setVariables("变量名", "变量值"):设置变量(同vars.put())
  • ctx.getProperties("属性名"):获取属性值(同props.get())
  • ctx.setProperties("属性名","属性值"):设置属性(同props.put())
  • ctx.getPreviousResult():获取当前请求的请求结果(同prev)返回结果是SampleResult类型
  • ctx.getCurrentSampler():获取当前采样器的请求信息,返回结果是Sampler类型
  • ctx.getPreviousSampler():获取前一采样器请求信息,返回结果是Sampler类型
  • ctx.getThreadNum():获取当前线程数,从0开始
  • ctx.getThreadGroup():获取当前线程组
  • ctx. getThread():获取当前线程
  • ctx.getEngine():获取引擎
  • ctx.isSamplingStarted():判断采样器是否启动
  • ctx.isRecording():判断是否开启录制
  • ctx.getSamplerContext():获取采样器上下文数据

使用示例1

import org.apache.jmeter.samplers.SampleResult;

//可以查看JavaDoc,ctx.getPreviousResult()返回值是SampleResult类型;
SampleResult result = ctx.getPreviousResult();// 获取取样器结果
String responseString = result.getResponseDataAsString();// 获取响应数据
String responseCode = result.getResponseCode();// 获取响应码
String RequestHeaders = result.getRequestHeaders();// 获取请求头
String ResponseHeaders = result.getResponseHeaders();// 获取响应头

String request = ctx.getCurrentSampler().getPath();   //请求路径
String request = ctx.getCurrentSampler().getArguments().getArgument(0).getValue(); //获取json格式的请求参数


log.info("获取取样器结果:"+responseString);
log.info("获取响应数据:"+responseCode);
log.info("获取响应码:"+RequestHeaders);
log.info("获取请求头:"+RequestHeaders);
log.info("获取响应头:"+ResponseHeaders);

使用示例2

import org.json.*;
import org.json.JSONArray;  //需要的Json jar包在文末的网盘
import org.json.JSONObject;
import java.util.*;
import org.apache.jmeter.samplers.SampleResult;

SampleResult resultSampleResult = ctx.getPreviousResult();// 获取取样器结果
String responseString = resultSampleResult.getResponseDataAsString();// 获取响应数据
JSONObject responseJson = new JSONObject(responseString);  //将String的response转为JSON对象
String now_follow_by = responseJson.getJSONArray("data").getJSONObject(0).getString("follow_by"); //获取当前跟进的规划师

SamplerData

适用元件:BeanShell断言
data和SamplerData就是sampler data(请求数据),其类型为byte[ ]

// byte与String类型转换 String s = new String(bytes);
String samplerData = new String(data); 

//String samplerData = new String(data,"UTF-8"); //有中文乱码处理

Label / SampleLabel

Label 适用元件:BeanShell 取样器
SampleLabel 适用元件:BeanShell断言
Label和SampleLabel是sampler的标题,其类型是String。

//Label

String Label_title=Label;
log.info(""+Label_title);

//SampleLabel
String sampleLabel_title=SampleLabel;
log.info("Label_title:"+sampleLabel_title);

IsSuccess

适用元件:BeanShell 取样器
IsSuccess是一个反映采样器是否成功的java.lang.Boolean。如果设置为true,,否则,则为"失败"。
IsSuccess表示sampler的成功失败,其类型为boolean。

IsSuccess=true; //使采样器"通过"
IsSuccess=false;//使采样器"失败"

prev / SampleResult

JavaDoc
prev 适用元件:BeanShell 预处理程序、后置处理器、定时器
SampleResult 适用元件:BeanShell 取样器、BeanShell断言
prev和SampleResult是当前sampler的结果,其类型为SampleResult,它可以读写sampler的信息和控制sampler的行为。

prev常用方法

String RequestHeaders = prev.getRequestHeaders();   // 获取请求头
String ResponseHeaders = prev.getResponseHeaders(); // 获取响应头
String responseCode = prev.getResponseCode(); // 获取响应码
String responseData = prev.getResponseDataAsString(); // 获取响应数据
String ContentType  = prev.getContentType() //获取取样器响应Content-Type首部字段的值域(包含参数)
log.info(RequestHeaders);
log.info(ResponseHeaders);
log.info(responseData);

import org.apache.jmeter.samplers.SampleResult;
String samplerData= prev.getSamplerData(); //获取请求内容
log.info("getSamplerData=======:"+samplerData);

//停止线程
prev.setStopThread(true);//使用场景:如果断言失败,后面的接口不需要再跑,直接是脚本停止

SampleResult常用方法

import org.apache.jmeter.samplers.SampleResult;
SampleResult resultSampleResult = ctx.getPreviousResult();// 获取取样器结果

String responseData  = SampleResult.getResponseDataAsString(); //获取响应数据
String responseCode  = SampleResult.getResponseCode(); //获取响应码 HTTP: 200 、502、404等
String sampleLabel   = SampleResult.getSampleLabel(); //接口名称
String url = SampleResult.getUrlAsString() ; //请求url
String samplerData   = SampleResult.getSamplerData() ; //请求数据 ;请求url、请求body
String requestHeaders= SampleResult.getRequestHeaders() ; // 请求header
boolean status = SampleResult.isResponseCodeOK(); // HTTP 返回 200时为true

SampleResult.setSuccessful(false); //使请求失败

ResponseData

适用元件:BeanShell断言
ResponseData就是sampler response data(响应数据),其类型为byte []:

// String samplerData = new String(ResponseData); //byte与String类型转换 String s = new String(bytes);
String samplerData = new String(ResponseData,"UTF-8");//中文乱码处理
log.info("ResponseData"+samplerData);

ResponseCode/ResponseMessage

适用元件:BeanShell 取样器、BeanShell断言
ResponseCode、ResponseMessage 是响应报文的响应码和响应信息,其类型为String,可读可写;

log.info("响应码:"+ResponseCode);
log.info("请求头:"+ResponseHeaders);

Failure/FailureMessage/设置响应断言

适用元件:BeanShell断言
Failure和FailureMessage是BeanShell Assertion组件独有的内置变量,其作用是设置当前sampler的测试结果(成功或失败),Failure的类型是boolean,FailureMessage的类型是String。
结合if判断通过变量Failure=false或Failure=true来设置断言是否通过,当设置Failure=true时,还可以设置FailureMessage来设置失败原因。
变量说明:

  • Failure = false; //断言成功 - 预期结果与实际结果一致
  • Failure = true; //断言失败 - 预期结果与实际结果不一致
  • FailureMessage = "断言失败描述";

使用示例1:对状态码断言

//状态码断言
log.info("状态码:" + ResponseCode);
if(ResponseCode.equals("200")){ 
        Failure=false;
}
else{
        Failure=true;
        FailureMessage="响应状态码非200";  //指定失败原因
}

示例2:响应体包含特定字符

//获取响应数据
String response = prev.getResponseDataAsString();
log.info("响应体:" + response);
//响应数据包含
if(response.contains("登录成功")){
    Failure=false;
}
else{
    Failure=true;
    FailureMessage="响应数据不包含登录成功";
}

示例3:JSON响应体字段提取及断言

将String类型的响应体转为JSON对象并操作需要额外的jar包,可以使用org.json或gson,以json.jar为例,下载后将其放入JMeter/lib目录下,重启JMeter,添加BeanShell断言,如下:

//JSON响应断言
import org.json.*;   //导入org.json包  //需要的Json jar包在文末的网盘
String response = prev.getResponseDataAsString();  //获取响应数据
JSONObject responseJson = new JSONObject(response);  //转为JSON对象
String message = responseJson.getString("message"); 
log.info("响应message字段:" + message);
if(message.equals("成功")){
    Failure=false;
}
else{
    Failure=true;
    FailureMessage="响应message字段非成功";
}

json.jar百度下载 ,提取码:gard

FileName

适用元件:BeanShell 取样器
FileName是一个java.lang.String,它包含一个BeanShell脚本文件名(在BeanShell采样器的"脚本文件"节中输入的)。

Arguments对象

由于个人知识有限,没搞明白这个对象的原理,这里主要演示Arguments的使用场景:数据请求读取。

获取请求信息(在前置处理器使用):

import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.config.Argument;

//获取请求的 url
String url = sampler.getPath(); 

//json格式的请求数据
Arguments arguments = sampler.getArguments(); // 调用时注意sampler小写
String requestBody = arguments.getArgument(0).getValue();

//表单格式的请求数据
Arguments arguments = sampler.getArguments();
String fileType =arguments.getArgument(0).getValue();
String fileName = arguments.getArgument(1).getValue();

简写(在后置处理器使用):

//不需要导入Arguments
String requestBody = sampler.getArguments().getArgument(0).getValue();; // 调用时注意sampler小写
//请求为表单
String fileType = sampler.getArguments().getArgument(0).getValue();
String fileName = sampler.getArguments().getArgument(1).getValue();

表单请求方式,获取请求的key和Value:

import org.apache.jmeter.config.Arguments;
import java.util.Map.Entry;

Arguments args = sampler.getArguments();
Map map = args.getArgumentsAsMap();
log.info("==============:"+args.getClass().toString());
Iterator itor = map.entrySet().iterator();
while(itor.hasNext()){
     Entry entry = (Entry) itor.next();
     log.info("==========key:"+entry.getKey());  
     log.info("========Value:"+entry.getValue());  
}

循环读取请求参数(表单请求的)

import org.apache.jmeter.config.Argument;
import org.apache.jmeter.config.Arguments;

Arguments argz = ctx.getCurrentSampler().getArguments();
for (int i = 0; i < argz.getArgumentCount(); i++) {
    Argument arg = argz.getArgument(i);
    String a = arg.getValue();
    log.info("Value:"+a);
    vars.put("EMAIL",a);
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,468评论 5 473
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,620评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,427评论 0 334
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,160评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,197评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,334评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,775评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,444评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,628评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,459评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,508评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,210评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,767评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,850评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,076评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,627评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,196评论 2 341

推荐阅读更多精彩内容