jmeter的beanshell脚本开发
一、Beanshell内置变量介绍
Beanshell有一些默认的内置变量,用户可以通过这些变量与JMeter进行交互,其中主要的变量及其使用方法如下:
log:写入信息到控制台中,帮助调试脚本。log 打印日志,写入信息到jmeber.log文件
vars: 操作jmeter变量,生成/更新/获取当前脚本的jmeter变量
props: 操作jmeter属性,生成/更新/获取当前脚本的jmeter属性,使用方法和vars一样
ctx:获取当前线程上下文,可获取当前线程的请求信息和相应信息(eg:可以获取Http请求和响应的所有数据)
prev:获取当前请求的结果
2.SampleResult 获取SampleResult对象,能通过这个对象获取想要的信息。
3.Response 获取Response对象,能通过这个对象获取响应信息。
4.Failure 查看接口调使用能否成功,假如返回false是成功的,true是失败的。
5.FailureMessage 失败信息,没有设置的时候失败信息是空的,能set这个信息。
6.ResponseData 获取response body类型是byte[]。
7.ResponseCode 返回接口code成功是200。
8.ResponseMessage 获取msg成功是OK。
9.ResponseHeaders 获取接口服务端返回的头部信息。
10.RequestHeaders 获取用户端请求的头部信息。
11.SampleLabel 获取接口请求的名称。
12.SamplerData 获取请求的url和body。
13.ctx 代表上下文信息,能直接用。
14.vars即JMeterVariables,操作jmeter变量,这个变量实际引用了JMeter线程中的局部变量容器(本质上是Map),常用方法:
a) vars.get(String key):从jmeter中获得变量值;
b) vars.put(String key,String value):数据存到jmeter变量中;
15.prev 获取前面的sample返回的信息,常用方法:
a) getResponseDataAsString():获取响应信息。
b) getResponseCode() :获取响应code。
二、Beanshell Sampler 示例
- vars/props/log
通过Beanshell Sampler,测试人员可以编写一些特定逻辑生成的数据,并且通过vars.get、vars.put 或者props.get、props.put 把相应的变量传递到Jmeter脚本当中。
比如有些程序对身份证有校验,就可以在Beanshell脚本中编写身份证生成的逻辑,通过代码生成满足位数以及省市区编码校验的身份证号,然后把生成的身份证号作为变量保存到vars或者props当中,供后续接口调用。
vars.get(String,String) 可以获取Jmeter中已经生成的变量 vars.put(String,String) 可以创建和更新Jmeter变量 props.get(String,String) 可以获取Jmeter中已经生成的属性 props.put(String,String) 可以创建和更新Jmeter属性 vars和props的区别是前者是变量,只能在同一线程组内传递,后者是属性,可以在整个测试计划中跨线程组传递。 log.info(String) 可以将信息输出到控制台,方便代码调试
三、Beanshell Postprocessor 示例
- ctx/prev
ctx内置变量可以获取上下文,通常和Beanshell PostProcessor结合起来使用,用于解析请求的结果,具体代码如下所示。在Jmeter的Beanshell脚本编辑器里可以直接引用Jmeter的Jar包,Jmeter Jar包的Api参见官网(http://jmeter.apache.org/api/overview-summary.html )
prev等同于ctx.getPreviousResult(),通过prev可以直接获取到响应结果
四、Beanshell编写案例脚本
1、uuid转成32位长度
import java.util.UUID;
String id=UUID.randomUUID().toString().replaceAll("-","");
vars.put("ywzj",id);
2、请求参数字符串拼接
关联参数设置获取所有
int total = ${ldxxbh_matchNr};
log.info("ldxxbh总个数:" + ${ldxxbh_matchNr});
String ldxxbhAll = "";
if(total!=0){//接收返回数据非空时才执行拼装多个ldxxbh
for(int i=1;i<=total;i++){
String ldxxbhStr = vars.get("ldxxbh_"+i);
ldxxbhAll = ldxxbhAll + "{\"ldxxbh\":\"" + ldxxbhStr + "\", \"ack\": \"1\"},";
}
}else{
ldxxbhAll = "{\"ldxxbh\":\"" + "\", \"ack\": \"1\"},";
}
ldxxbhAll = ldxxbhAll.substring(0,ldxxbhAll.length()-1);
//log.info("变量值:"+ldxxbhAll);
vars.put("ldxxbhPar",ldxxbhAll);
//log.info("参数值:" + vars.get("ldxxbhPar"));
3、返回数据写入文本
import java.io.FileWriter;
import java.io.IOException;
int num=${ywzjid_matchNr};
log.info("ywzjid总个数:" + num);
if(num!=0){//num非空时才执行写入数据
for(int i=1;i<=num;i++){
String ywzjid = vars.get("ywzjid_"+i);
String fileName = "ywzjid.txt";
FileWriter fw = new FileWriter(fileName, true);
fw.write(ywzjid);
fw.write("\r\n");
fw.close();
}
}
4、jmeter引入自己的jar包,beanshell中路径需要写到类名
将jar包放入jmeter\lib下
import com.test.secure.secure.des.DESCoderHelper;
DESCoderHelper des = new DESCoderHelper();
String key = "12345678";
String paramsSecret = des.encryptNetString(params,key);
vars.put("paramsSecretP",paramsSecret);
5、日志处理
需使用断言中的beanshell断言,若使用的是后置处理器则不正确。
String response = prev.getResponseDataAsString();
String str = "\"Code\":\"000\"";
boolean a = response.contains(str);
if(a==true){
Failure=false;//断言成功
//FailureMessage = "pass:" + response;
//log.info(FailureMessage);
}else{
Failure=true;//断言失败
FailureMessage = "fail:" + vars.get("code");//response
log.info(FailureMessage);
}
字符串包含判断
String response = "";
String Str = "JMeter性能测试2";
response = prev.getResponseDataAsString();//获取当前请求响应结果
if(response == "")
{
Failure = true;
FailureMessage = "系统无响应,获取不到响应数据";
log.info(FailurMessage);
}else if(response.contains(Str)==false){
Failure = true;
String msg = "\n系统返回响应结果与预期结果不一致!请排查是性能问题,还是程序代码问题";
FailureMessage = msg + "\n" + "期望结果:\n" + Str + "\n" + "响应内容:\n" + response + "\n";
log.info(FailureMessage);
}else{
Failure=false;
}
6、时间处理
SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
String date = df.format(new Date());
vars.put("date",date);
7、跨线程组变量使用,设置全局变量
应用场景:登录无法支持500并发,但其他场景需要测试500并发时,只需使用一次登录的cookie即可
登录场景单独一个线程组,设置全局变量
${__setProperty(p_session,${access_token},)}
另外线程组使用
${__P(p_session,)}
8、左右边界查找,碰到请求头换行的响应内容获取处理
${__unescape(\n)}
9、线程组和执行时间参数化
${__P(threads5,0)}
${__P(duration,0)}
10、base64位加密和解密函数
base64加密函数
${__base64Encode({"qtId":"cd4a8ed50eca449a82556aae38b6af97"\,"batchId":"cd4a8ed50eca449a82556aae38b6af97"\,"drtk":"502ad80d34b7de6408ba677506ac52ce"},dataBase64Encode)};
dataBase64Encode为存储加密内容的参数名
base64解密函数
${__base64Decode(eyJxdElkIjoiY2Q0YThlZDUwZWNhNDQ5YTgyNTU2YWFlMzhiNmFmOTciLCJiYXRjaElkIjoiY2Q0YThlZDUwZWNhNDQ5YTgyNTU2YWFlMzhiNmFmOTciLCJkcnRrIjoiNTAyYWQ4MGQzNGI3ZGU2NDA4YmE2Nzc1MDZhYzUyY2UifQ==,dataBase64Decode)};