JMeter之BeanShell內置方法的使用

前言

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

本文主要介紹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 支持的變量不一樣,直接使用會報錯。如下圖,可以通過元件知道支持什么變量。如圖,可以根據遠見的說明知道支持什么變量。


image-20220504165831908.png
  • 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的控制臺(黑框里)");

日志顯示位置:


image-20220504170620220.png

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);
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容