一、什么是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):
sampler | 是類Sampler的對象,表示當前采樣器 |
---|
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
sampleEvent | SampleEvent,具體內部方法,請看 |
---|
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);