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

  • 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

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); }