【测试工具JMeter篇】JMeter性能测试入门级教程(四):JMeter中BeanShell内置方法使用

一、什么是BeanShell

  • BeanShell是一种完全符合Java语法规范的脚本语言,并且又拥有自己的一些语法和方法;
  • BeanShell是一种松散类型的脚本语言(这点和JS类似);
  • BeanShell是用Java写成的,一个小型的、免费的、可以下载的、嵌入式的Java源代码解释器,具有对象脚本语言特性,非常精简的解释器jar文件大小为175k。
  • BeanShell执行标准Java语句和表达式,另外包括一些脚本命令和语法。

二、JMeter中有哪些BeanShell

  • 定时器:  BeanShell Timer

  • 前置处理器:BeanShell PreProcessor

  • 采样器:  BeanShell Sampler

  • 后置处理器:BeanShell PostProcessor

  • 断言:   BeanShell断言

  • 监听器:  BeanShell Listener

三、BeanShell元件所支持的变量

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

  • 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,适用元件、适用例子,其中适用例子都是自己调试过的,可以直接复制粘贴使用。

1. log

JavaDoc

适用元件:除了监听器,其他元件都可使用。

log表示org.apache.log.Logger类,日志信息写入到jmeter.log文件。

  • log.info("响应状态码" + ResponseCode);

  • log.debug("调试信息");

  • log.warn("警告信息");

  • log.error("出错信息");

    log.info("这里的信息会保存在jmeter.log文件中,并打印显示在jmeter的实时运行日志");

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

日志显示位置:

2. 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);

3. 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,)}获取全局属性的值。

4. 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"); //获取当前跟进的规划师

5. 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"); //有中文乱码处理

6. 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);

7. IsSuccess

适用元件:BeanShell 取样器

IsSuccess是一个反映采样器是否成功的java.lang.Boolean。如果设置为true,,否则,则为"失败"。

IsSuccess表示sampler的成功失败,其类型为boolean。

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

8. 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); //使请求失败

9. 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);

10. ResponseCode/ResponseMessage

适用元件:BeanShell 取样器、BeanShell断言

ResponseCode、ResponseMessage 是响应报文的响应码和响应信息,其类型为String,可读可写;

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

11. 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

12. FileName

适用元件:BeanShell 取样器

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

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

五、经典实例

最好用一个我刚好在调的一个BeanShell应用结尾:

场景:在压力测试下,有这样的场景:有4个线程组1、2、3、4,比例分配依次是10%、20%、30%、40%,如果总并发需要分别尝试1000、2000、3000、4000就要都分别修改,可不可以只修改总并发一个地方,实现方式可参考如下:

1. setUp Thread Group里设置总并发

2. 分别配置线程组1、2、3、4(${__P(threads1,)})

3. 运行结果如下

BeanShell是很强大的,但是得对Java的基础知识有些基本了解才能很好地运用。同时运用的好,可以解决我们在测试过程中碰到的好些问题。

相关推荐
程序员油条1 小时前
postman使用正则表达式提取数据实战篇!
测试工具·正则表达式·postman
开水好喝6 小时前
IDE如何安装插件实现Go to Definition
javascript·ide·vscode·测试工具
斗-匕8 小时前
JVM 垃圾回收详解
jvm·测试工具
qq_白羊座1 天前
MeterSphere VS 其他开源接口测试工具
测试工具·metersphere
测试界兮兮1 天前
基于jmeter+perfmon的稳定性测试记录
自动化测试·软件测试·功能测试·jmeter·程序人生·单元测试·压力测试
月光技术杂谈2 天前
基于rpcapd与wireshark的远程实时抓包的方法
网络·测试工具·wireshark
ggdpzhk2 天前
SpringBoot项目:Postman请求响应
测试工具·postman
土小帽软件测试2 天前
jmeter基础07_组件的层级
测试工具·jmeter·软件测试学习
明月与玄武2 天前
如何搭建JMeter分布式集群环境来进行性能测试
分布式·jmeter
幸福的达哥2 天前
JMeter中获取随机数、唯一ID、时间日期(包括当前日期增减)截取指定位数的字符等
python·测试工具·postman