前言
本文是自己在日常使用過程中整理前輩們的知識,以及自己日常使用整理輸出的結果,由于匯集了過多的文章、時間太長,無法一一列舉曾經引用過哪些前輩了,實屬抱歉。也限于個人水平有限,若有哪些寫得不對的也歡迎指正。
本文主要介紹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);
}