『動善時』JMeter基礎 — 31、JMeter中BeanShell斷言詳解

繁華似錦Fighting發表於2021-06-02

JMeter中的BeanShell斷言,可以使用BeanShell指令碼來執行斷言檢查,可以用於更復雜的個性化需求,使用更靈活,功能更強大,但是要能夠熟練使用BeanShell語。

1、BeanShell簡介

Beanshell是一種類似JAVA的指令碼語言,通過BeanShell可以對請求資料、響應資料或環境變數進行更加靈活的處理和判斷。還可以直接呼叫外部的JAR包,例如:可以直接引入現成的第三方JSON解析包來使用。

在JMeter的多種元件中都有BeanShell的身影,如下:

  • 定時器:BeanShell Timer
  • 前置處理器:BeanShell PreProcessor
  • 取樣器:BeanShell Sampler
  • 後置處理器:BeanShell PostProcessor
  • 斷言:BeanShell Assert
  • 監聽器:BeanShell Listener

在JMeter執行的流程控制中,BeanShell出現的位置,如下圖所示:

image

2、Beanshell的內建變數和方法

Beanshell有一些預設的內建變數和方法,使用者可以通過這些變數與JMeter進行互動,

例如:

  • prInt:非GUI模式下列印資訊(輸出資訊到stdout,標準輸出控制檯)。
  • log:輸出資訊到日誌(檔案)
    • log.debu("除錯資訊")
    • log.info("響應狀態碼" + ResponseCode)
    • log.warn("警告資訊")
    • log.error("出錯資訊")
  • ResponseCode:響應狀態碼(String型別)。
  • ResponseHeaders:響應頭(String型別)。
  • prev:獲取當前請求結果
    • prew.getResponseDataAsString():獲取響應體資料(String型別)。
    • prew.getResponseCode():獲取狀態碼(同ResponseCode,String型別)。
  • vars:操作JMeter變數
    • String var1 = vars.get("變數名"):獲取變數的值(假設為String型別)。
    • vars.put("變數名", 變數值):設定變數值。
  • props:操作JMeter屬性
    • props.get(String,String) 可以獲取JMeter中已經生成的屬性。
    • props.put(String,String) 可以建立和更新JMeter屬性。
  • ctx:獲取當前執行緒上下文資料(可獲取所有資訊)
    • ctx.getVariables("變數名"):獲取變數值(同vars.get())。
    • ctx.setVariables("變數名", "變數值"):設定變數(同vars.put())。
    • ctx.getProperties("屬性名"):獲取屬性值(同props.get())。
    • ctx.setProperties("屬性名","屬性值"):設定屬性(同props.put())。
    • ctx.getPreviousResult():獲取當前請求結果同(prev)。
    • ctx.getCurrentSampler():獲取當前取樣器。
    • ctx.getPreviousSampler():獲取前一取樣器。
    • ctx.getThreadNum():獲取執行緒數。
    • ctx.getThreadGroup():獲取執行緒組。
    • ctx. getThread():獲取當前執行緒。
    • ctx.getEngine():獲取引擎。
    • ctx.isSamplingStarted():判斷取樣器是否啟動。
    • ctx.isRecording():判斷是否開啟錄製。
    • ctx.getSamplerContext():獲取取樣器山下文資料。

提示:ctx詳細API可參考:JMeter上下文

3、BeanShell斷言介面詳解

新增BeanShell斷言元件操作:選中“取樣器”右鍵 —> 新增 —> 斷言 —> BeanShell斷言

介面如下圖所示:

image

BeanShell斷言元件的詳細說明:

  • 名稱BeanShell斷言元件的自定義名稱,見名知意最好。
  • 註釋:即新增一些備註資訊,對該BeanShell斷言元件的簡短說明,以便後期回顧時檢視。
  • Reset bsh.Interpreter before each call:每個BeanShell測試元素都有自己的直譯器副本(對於每個執行緒)。如果重複呼叫測試元素,例如在迴圈內,除非選擇在每次呼叫之前重置bsh.Interpreter選項,否則直譯器將保留在呼叫之間。一些長時間執行的測試可能會導致直譯器使用大量記憶體。
    由於BeanShell的bsh.Interpreter存在記憶體洩露,常規方法無法支援長時間的壓力測試。JMeter官網推薦,在使用BeanShell進行長時間測試時,開啟選項Reset bsh.Interpreterbefore each call,則在每次呼叫BeanShell程式前,都把直譯器重置,以釋放直譯器之前佔用的記憶體。
  • 引數 (-> String Parameters和String[]bsh.args):輸入String引數。String []bsh.args是主類main函式的形式引數,是一個String 物件陣列,可以用來獲取命令列使用者輸入進去的引數。
  • 指令碼檔案:指令碼檔案(可以填入指令碼檔案路徑),可以點選後邊的瀏覽選擇指令碼檔案。
  • Script (see below for variables that are defined):編寫指令碼,參照下文定義的變數(使指令碼檔案參照定義的變數來執行)

4、BeanShell斷言的使用

BeanShell斷言中可以通過ResponseCodeResponseHeaderspre.getResponseDataAsString()來分別獲得String格式的響應狀態碼、響應頭、響應體資料。結合if判斷,通過變數Failure=falseFailure=true來設定斷言是否通過。當設定Failure=true時,還可以設定FailureMessage來設定失敗原因。

我們以一個登陸介面,來演示BeanShell斷言元件的應用。

(1)測試計劃內包含的元件

新增元件操作步驟

  1. 建立測試計劃。
  2. 建立執行緒組:選中“測試計劃”右鍵 —> 新增 —> 執行緒(使用者) —> 執行緒組
  3. 線上程組裡面,新增取樣器“HTTP請求”元件:選中“執行緒組”右鍵 —> 新增 —> 取樣器 —> HTTP請求
  4. 在取樣器下,新增斷言“BeanShell斷言”元件:選中“取樣器”右鍵 —> 新增 —> 斷言 —> BeanShell斷言
  5. 在取樣器下,新增監聽器“斷言結果”元件:選中“取樣器”右鍵 —> 新增 —> 監聽器 —> 斷言結果
  6. 線上程組裡面,新增監聽器“察看結果樹”元件:檢視結果,選中“執行緒組”右鍵 —> 新增 —> 監聽器 —> 察看結果樹

最終測試計劃中的元件如下:

image

點選執行按鈕,會提示你先儲存該指令碼,指令碼儲存完成後會直接自動執行該指令碼。

(2)登陸介面請求介面內容

標準的Post請求,填寫請求的基本資訊和引數即可。

編寫內容如下:

image

(3)BeanShell斷言介面內容

我把只要把自己編寫的BeanShell程式碼,複製到Script (see below for variables that are defined)下的輸入框即可。

如果需要進行模擬壓力測試的時候,可以勾選上Reset bsh.Interpreter before each call選項。我們這裡不用。

編輯好的介面,如下圖所示:

image

說明

1)狀態碼斷言程式碼

//狀態碼斷言
log.info("狀態碼:" + ResponseCode);
if(ResponseCode.equals("200")){ 
	Failure=false;	// 表示斷言成功
}
else{
	Failure=true;	// 表示斷言失敗
	FailureMessage="響應狀態碼非200";  // 自定義的失敗資訊
}

注:字串只能使用雙引號,字串相等要使用" ".equals(" ")表示式。

2)響應體包含特定內容斷言程式碼

//獲取響應資料
String response = prev.getResponseDataAsString();
log.info("響應體:" + response);
//響應資料包含
if(response.contains("登入成功")){
	Failure=false;	// 表示斷言成功
}
else{
	Failure=true;	// 表示斷言失敗
	FailureMessage="響應資料不包含登入成功";
}

(4)檢視執行結果

我們在察看結果樹元件中,觀察指令碼執行之後的結果。

如果斷言正確,和正常傳送請求一樣,如下圖:

image

如果斷言失敗,則會出現斷言失敗的提示,如下圖所示:

image

(5)斷言結果元件說明

也新增斷言結果監聽器,通過斷言結果元件來判斷斷言是否通過。

如下圖所示:

image

說明:

  • 已通過的斷言僅顯示取樣器名稱。
  • 未通過的,除了顯示取樣器的名稱,還顯示錯誤原因。

5、補充知識點

(1)JSON響應體欄位提取及斷言

將String型別的響應體轉為JSON物件並操作需要額外的JAR包,可以使用org.json.jargson.jar

json.jar為例,下載後將其放入JMeter/lib目錄下,重啟JMeter,新增BeanShell斷言程式碼,如下:

//JSON響應斷言
import org.json.*;   //匯入org.json包

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欄位非成功";
}

JSONObject物件除了getString()方法外,還支援:

  • getBoolean("欄位名") :獲取布林型別欄位值。
  • getInt("欄位名"):獲取整型欄位值。
  • getLong("欄位名"):獲取長整型欄位值。
  • getDouble("欄位名"):獲取雙精型欄位值。
  • getJSONObject("欄位名"):獲取巢狀Object型別欄位值,JSONObject型別。
  • getJSONArray("欄位名"):獲取巢狀Array型別,JSONArray型別。

(2)響應頭解析

響應頭原本為String型別,可以通過分割遍歷組裝成Map型別來提取響應頭中的項

Copyimport java.util.HashMap;
import java.util.Map;

//將字串用換行符 擷取為adc陣列
String [] headersList = ResponseHeaders.split("\n");

Map headersMap = new HashMap();   //建立HashMap來從新組裝headers

for(int i=1;i<headersList.length;i++){
	String [] itemList=headersList[i].split(": ");   // 將每一條Headerr項按冒號分割
	headersMap.put((itemList[0]), itemList[1]);   // 分鍵值放入HashMap
}

String contentType = headersMap.get("Content-Type");   // 提取相應項
log.info("響應Content-Type:" + contentType)

參考:https://www.cnblogs.com/superhin/p/12359794.html

相關文章