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 支持的变量不一样,直接使用会报错。如下图,可以通过元件知道支持什么变量。
- 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的控制台(黑框里));
日志显示位置:
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); }