一、BeanShell可以做什么?
1、读写请求、响应相关的信息(包括请求头、请求信息、响应头、响应码、响应体等)
2、执行Java代码实现一定逻辑计算(请求加密、复杂的断言方式);
3、其它:
数据库断言。
RSA加加密,混合加密
接口签名
调用开发给的jar包,class文件,java文件,
CSV数据驱动之后的断言;
跨线程组共享变量;
二、Jmeter中关于BeanShell的有:
1.BeanShell Sampler 取样器:完成Beanshell请求组件中定义的脚本功能;
2.BeanShell PostProcessor 后置处理器:可通过编程方式获取对应请求的响应结果;
3.BeanShell PreProcessor 前置处理器:可通过编程方式在发起请求以前做预处理,比如编码或者加密;
4.Beanshell 断言:可通过编程方式实现复杂的断言逻辑;
5.Beanshell 计时器:编码实现条件定时功能;
6.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
具体查看方式:可以在每个元件的下方查看,例如
三、常用的Beanshell方法
重点掌握:内置变量vars、props、prev的使用
1、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的控制台(黑框里)”);
日志显示位置:
2、vars
javaDOC
官方文档:https://jmeter.apache.org/api/org/apache/jmeter/threads/JMeterVariables.html
适用元件:所有元件
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”)); 可点击了解:JMeter之JDBC连接/操作数据库
注意: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());
其他:vName = vars.remove(“name”);删除一个变量,并返回变量的值,若变量不存在则返回 null
3、props
适用元件:所有元件
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()
常用方法:(使用场景:跨线程使用)
//返回属性列表中所有key的枚举,如果在主属性列表中未找到同名的key,则包括默认属性列表中不同的key
props.propertyNames();
propsNames.each{
log.info(it)
}
//返回有多少个属性
pPropsCount = props.size();
log.info(“pPropsCount:”+ pPropsCount);
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,)}获取全局属性的值。
vars跟props的区别
vars 是对变量进行读写操作, 而 props 主要是对属性进行读写操作
vars 只能在当前线程组内使用,props 可以跨线程组使用 ,因为属性可以跨线程组但是变量不行
vars 只能保存 String 或者 Object,props 可以是 Hashtable 或者 Object
实际使用场景举例:
1、线程组1中使用props.put(“phone”,“13712907379”);先设置全局变量;
2、线程组2中先使用props.get(“phone”)获取线程组1的全局变量;之后使用vars.put转换为局部变量,才可在另一个线程组使用
http请求中的参数设置
线程组2成功调用后的结果
4、ctx
适用元件:所有元件
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
prev 提供对当前取样器结果的访问能力,映射 org.apache.jmeter.samplers 的 SampleResult 类
官方文档: https://jmeter.apache.org/api/org/apache/jmeter/samplers/SampleResult.html
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类型的响应结果)
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);//使用场景:如果断言失败,后面的接口不需要再跑,直接是脚本停止
//判断响应状态码是否为OK对应的状态码(200),结果只有true和false
responseCodeBoolean = prev.isResponseCodeOK();
log.info("responseCodeBoolean:" + responseCodeBoolean);
//获取线程名
prevThreadName = prev.getThreadName();
log.info("prevThreadName:" + prevThreadName);
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字段非成功";
}
12、FileName
适用元件:BeanShell 取样器
FileName是一个java.lang.String,它包含一个BeanShell脚本文件名(在BeanShell采样器的"脚本文件"节中输入的)。
13、Arguments对象
Argument对象,JMeter内部给 取样器 接收请求的对象,所以可以通过Argument可以获取到请求参数,这里需要注意的是表单形式的请求与json格式的请求获取方式有些差异。
获取请求信息:
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();
简写:
这个方式可以跳过在非BeanShell 取样器中导入Argument而报错的问题。
//不需要导入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调用java文件及jar包
1、beanshell调用java文件;
2、beanshell调用jar包;
jar包在使用前,需要提前在【测试计划】中添加进去,之后才可使用;