一、什么是Bean Shell
- BeanShell是一种完全符合Java语法规范的脚本语言,并且又拥有自己的一些语法和方法;
- BeanShell是一种松散类型的脚本语言(这点和JS类似);
- BeanShell是用Java写成的,一个小型的、免费的、可以下载的、嵌入式的Java源代码解释器,具有对象脚本语言特性,非常精简的解释器jar文件大小为175k。
- BeanShell执行标准Java语句和表达式,另外包括一些脚本命令和语法。
官网:http://www.BeanShell.org/
二、Jmeter有哪些Bean Shell
-
- 定时器: BeanShell Timer
- 前置处理器:BeanShell PreProcessor
- 采样器: BeanShell Sampler
- 后置处理器:BeanShell PostProcessor
- 断言:BeanShell断言
- 监听器:BeanShell Listener
三、BeanShell内置对象
其中,每个BeanShell元件都有自己的内置对象,在元件上也有对应说明,当前元件的内置对象有哪些,比如BeanShell Sampler元件的底部有提示该元件有哪些内置对象。
log | 记录日志,Jmeter使用log4j记录日志,一般使用的比较多的是log.info()、log.error(),打印的日志会记录到bin/jmeter.log文件 |
---|---|
props | 操作Jmeter属性,即jmeter.properties文件的配置 |
props.get("https.use.cached.ssl.context"): 获取对应的属性值 | |
props.put("https.use.cached.ssl.context", false): 保存数据到Jmeter属性中,如果属性不存在就创建 | |
vars | 是类JMeterVariables的对象,具体内部方法使用,请看 操作Jmeter变量,需要注意Jmeter变量是在线程启动时,拷贝到线程的,类似线程的局部变量,所以一个线程更新了变量,不会影响到另一个线程 |
vars.get("name"): 从线程中获得变量值 | |
vars.put("key", "value"): 保存数据到线程中,如果变量不存在会创建 | |
ctx | 是类JMeterContext的对象,保存线程的上下文,该对象不是线程安全的,建议在单线程时使用,具体内部方法使用,请看 |
prev | 是类SampleResult的对象,保存前一个请求的信息,具体内部方法使用,请看 注意 根据作用域和执行顺序 可以知道,元件有在采样器前执行的,有在采样器后执行的,对于在采样器前执行的,prev表示的是前一个请求的信息,而对于在采样器后执行的,prev表示的当前请求的信息! |
data | 类型是byte[],即字节数组, 当前请求的响应数据,可以用String str = new String(data, "utf-8")转成字符串再打印出来 |
四、常见BeanShell 元件介绍
1.BeanShell Sampler
Parameters(3):传递给BeanShell脚本的参数,只能传递String字符串类型。有两种方式使用:
Parameters:单个字符串,则使用Parameters;
bsh.args:数组,空白处分割,比如a b c,那么bsh.args[0]=a。
Script file(4):包含要运行的BeanShell脚本的文件,文件名存储在变量FileName中,添加了脚本文件后,就只会运行添加的脚本文件,Script部分的脚本代码不会运行了。
Script(5):要运行的BeanShell脚本,返回值如果不为null,就存储为采样器结果。
内置对象(6):
SampleResult | 是类SampleResult的对象,保存当前请求和响应的信息,具体内部方法使用,请看 |
---|---|
ResponseCode | 响应的status code,默认为200 |
ResponseMessage | 响应信息,默认为"OK" |
IsSuccess | 请求是否成功,默认为true |
Label | 采样器的标签,即Name字段 |
FileName | 文件名,如果Script file有包含外部bsh文件 |
2.BeanShell PreProcessor
内置对象(4):
3.BeanShell PostProcessor
BeanShell后置处理器,可以用于处理响应数据。比如现在有一个接口返回的数据数据是加密的,也可以在后置处理器里先对响应数据做解密。
那么我们现在就通过BeanShell PostProcessor来将接口的返回数据修改为"Hello, World",写入如下代码:
byte[] b = "Hello,World".getBytes(); prev.setResponseData(b);
4.BeanShell Timer
定时器会让作用域内的每一个采样器都在执行前等待一个固定的时长,如果作用域内有多个定时器,那这多个定时器就会在采样器之前全部执行,所以多个定时器的延迟时长是每个定时器的延时时长的累加。
现在,我们想要一个采样器延迟3秒再执行,写入如下代码:
// 单位是毫秒 Thread.sleep(3000);
从日志文件bin/jmeter.log中可以看到采样器延迟了3秒。
5.BeanShell Assertion
可以看到BeanShell断言的内置对象很多,可读/可写的意思是我们可以更改,比如说SampleResult是当前请求响应的数据,说白了,在BeanShell断言里同样可以修改响应数据,和BeanShell后置处理器一样。
Failure | boolean,用来设置断言状态,为true,表明断言失败 |
---|---|
FailureMessage | String,用来设置断言信息 |
SampleResult | SampleResult,具体内部方法,请看 |
Response | SampleResult,具体内部方法,请看 |
ResponseData | byte[],响应数据 |
ResponseCode | String,status code的值,比如200,404 |
ResponseMessage | String,响应信息,比如OK |
ResponseHeaders | String,响应头 |
RequestHeaders | String,请求头 |
SampleLabel | String,采样器的Name |
SamplerData | String,就是截图中的内容 |
现在我们用ResponseCode来判断,等于200时,设置为通过,写入如下代码:
if ("200".equals(""+ResponseCode) == false ) { // 响应码不等于200时,设置断言失败,并输出失败信息 Failure=true ; FailureMessage ="Response code was not a 200 response code it was " + ResponseCode + "." ; print ( "the return code is " + ResponseCode); // this goes to stdout log.warn( "the return code is " + ResponseCode); // this goes to the JMeter log file } else { // 响应码等于200时,设置断言成功,并输出成功信息 Failure=false; FailureMessage = "Return true, and the response code was " + ResponseCode; }
6.BeanShell Listener
内置对象:
BeanShell监听器用相比较而言比较少
五、编写脚本
例如:现在线程有两个变量username=Augus,new_name=ls,我们需要读取username将new_name修改为"Hello, Augus"。
1、设置变量username=Augus,new_name=ls:
Jmeter设置变量的方式一共有4种:
1)Test Plan的User Defined Variables,
2)Config Element的User Defined Variables ,
3)Config Element的CSV Data Set Config,
4)Pre Processors的User Parameters
这里就直接使用Test Plan的User Defined Variables了
3、添加一个Sampler --> BeanShell Sampler,并先写入如下脚本:
public static void test(){ //定义一个变量 String inout; //获取变量aa所对应的值,赋值给input input = vars.get("username"); String output = "hello," + input; vars.put("new_name",output); } test()
4、添加一个Sampler --> Debug Sampler,命名为after
5、添加一个Listener --> View Results Tree
6、运行,查看结果:
1)引用源文件,即.java文件。
2)引用字节码文件,即.class文件。
3)引用jar包,即.jar文件。
public class BeanShellMethod { public static String test(String input) { String output = "hello," + input; return output; } }
引用源文件
Jmeter提供了source函数,来引用源文件。在BeanShell Sampler中写入如下代码:
//加载使用java文件 source("D:\\jmeterBeanShell\\BeanShellMethod.java"); //获取变量aa所对应的值 String str1 = vars.get("username"); //调用java文件中test函数,对于 String str2 = new BeanShellMethod().test(str1); //保存值 vars.put("password",str2);
运行,从after中可以看到new_name变量被修改了。
引用字节码文件
上面我们有了BeanShellMethod.java,可以将其编译为后缀为.class的字节码文件,方式如下:
javac BeanShellMethod.java
Jmeter提供了addClassPath函数,来引用字节码文件。在BeanShell Sampler中写入如下代码:
//加载class文件的路径 addClassPath("D:\\jmeterBeanShell"); //注意这里导入类,注意也有加; import BeanShellMethod; //获取aa变量的值 String str1 = vars.get("username"); //调用test方法 String str2 = new BeanShellMethod().test(str1); //赋值保存 vars.put("new_name",str2);
运行,从after中可以看到new_name变量被修改了。
引用外部jar包
Jmeter引用外部jar包方法:将jar包拷贝到jmeter/lib/ext目录下,这种需要重启Jmeter,才能加载这个jar包;
首先编辑java文件,然后再将.class文件打包成jar包,再将jar包拷贝到对应目录.然后在BeanShell Sampler中写入如下代码:
import hellotest.BeanShellMethod; //获取aa变量的值 String str1 = vars.get("username"); //调用test方法 String str2 = new hellotest.BeanShellMethod().test(str1); //赋值保存 vars.put("new_name",str2);
运行,从after中可以看到new_name变量被修改了。
六、其它用法(接受参数, log等)
1、在Test Plan中定义如下三个变量:
2、Bean Shell可脚本如下:
- a、bean shell可以接受传入参数,如下图:${name} ${age} ${sex}
- b、参数可以通过bsh.args[]按顺序提取
- c、bean shell提供了一个内置变量Parameters,来保存参数的集合
//获取参数传递过来的值并存入变量中 vars.put("v1",bsh.args[0]); vars.put("v2",bsh.args[1]); vars.put("v3",bsh.args[2]); //获取参数传递过来的变量集合 vars.put("v4",Parameters); //输出变量集合 log.info(Parameters); //输出该元件的name log.info(Label); //设置响应代码 ResponseCode = 500; //设置响应信息 ResponseMessage = "This is a BeanShell test"; //设置是否成功 IsSucces = false; //设置响应数据 SampleResult.setResponseData("hello world")
3、运行结果如下图:
下图中1输入的这两句设置:
ResponseCode = 500; ResponseMessage = ResponseMessage = "This is a BeanShell test";
下图中2输入的这两句设置:
这里需要注意,点击【选项】,勾选log Viewer,然后运行,可以查看运行的日志信息
//输出变量集合 log.info(Parameters); //输出该元件的name log.info(Label);