JMeter Beanshell 使用指南
一、簡介
在本快速教學中,我們將建立一個使用 JMeter 中提供的大部分BeanShell功能的測試案例。最終,我們將學習如何使用必要的工具來使用 BeanShell 腳本進行任何測試。
2. 設定JMeter和BeanShell
首先,我們需要下載 JMeter。要運行它,我們需要在任何地方解壓縮下載文件,然後運行可執行檔(對於基於 Unix 的系統為jmeter.sh
,對於 Windows 為jmeter.bat
)。
在撰寫本文時,最新的穩定版本是 5.6.3,它已經捆綁了 BeanShell 2.0b6 二進位。版本 3 目前正在開發中,將支援更新的 Java 功能。在那之前,我們一直堅持使用 Java 4 語法,儘管 JMeter 可以在最新的 JVM 上運行。稍後我們將看到這如何影響我們的腳本。
最重要的是,雖然 BeanShell 是一種功能豐富的腳本語言,但它主要用於在 JMeter 中實現測試步驟。我們將在我們的場景中實際看到這一點:在捕獲統計資料(例如發送的總位元組數和經過的時間)時向 API 發出 POST 請求。
啟動 JMeter 後,我們需要的唯一非 BeanShell 元素是線程組。我們透過右鍵單擊“測試計劃”,然後選擇“新增”,然後選擇“線程(使用者)”,然後選擇“線程組”來建立一個。我們只需要指定我們想要的線程和循環的數量:
完成後,我們就可以為我們的測試建立基於 BeanShell 的元素了。
3. 預處理器
我們將從預處理器開始為 POST 請求配置值。為此,我們右鍵單擊線程組,然後依次單擊“新增”、“預處理器”和“BeanShell 預處理器”。在其內容中,我們編寫一個腳本來為請求產生隨機值:
random = new Random();
key = "k"+random.nextInt();
value = random.nextInt();
要宣告變數,我們不需要明確包含它們的類型,並且可以使用 JVM 或 JMeter 的lib
資料夾中可用的任何類型。
讓我們使用vars
物件(腳本之間共享的特殊變數)來保存這些值以供以後使用,以及我們的 API 位址:
vars.put("base-api", "http://localhost:8080/api");
vars.put("key", key);
vars.putObject("value", value);
我們使用putObject()
來取得value
,因為put()
只接受String
值。我們的最終變數定義了當前線程應該列印摘要之前的測試迭代次數。我們稍後會用到它:
vars.putObject("summary-iterations", 5)
4. 採樣器
我們的採樣器會擷取先前儲存的值,並使用與 JMeter 捆綁在一起的 Apache HTTP 框架將它們傳送到 API。最重要的是,我們需要包含腳本中直接提到的任何不在預設導入清單中的類別import
語句。
為了建立請求正文,我們將使用String.format()
的較舊的new Object[]{…}
語法,因為varargs
是 Java 5 的功能:
url = vars.get("base-api");
json = String.format(
"{\"key\": \"%s\", \"value\": %s}",
new Object[]{ vars.get("key"), vars.get("value") }
);
現在,讓我們執行請求:
client = HttpClients.createDefault();
body = new StringEntity(json, ContentType.APPLICATION_JSON);
post = new HttpPost(url);
post.setEntity(body);
response = client.execute(post);
JMeter 包括ResponseCode
和ResponseMessage
變量,我們將在稍後階段檢索它們:
ResponseCode = response.getStatusLine().getStatusCode();
ResponseMessage = EntityUtils.toString(response.getEntity());
最後,由於我們無法使用 try-with-resources 區塊,因此我們關閉資源並為腳本選擇一個回傳值:
response.close();
client.close();
return json;
返回可以是任何類型。我們稍後將返回請求正文以計算請求大小。
5.後處理器
後處理器在採樣器之後立即執行。我們將使用它來收集和匯總我們需要的資訊。讓我們建立一個函數來遞增變數並保存結果:
incrementVar(name, increment) {
value = (Long) vars.getObject(name);
if (value == null)
value = 0l;
value += increment;
vars.putObject(name, value);
log.info("{}: {}", name, value);
}
在這裡,我們還有一個無需額外配置的記錄器。它將記錄到 JMeter 控制台。請注意,可見性修飾符、傳回類型和參數類型不是必需的;它們是從上下文推斷出來的。
我們將增加每次執行緒迭代所花費的時間和發送/接收的位元組數。 prev
變數讓我們可以從上一個腳本中取得該資訊:
incrementVar("elapsed-time-total", prev.getTime());
incrementVar("bytes-received-total", prev.getResponseMessage().getBytes().length);
incrementVar("bytes-sent-total", prev.getBytesAsLong());
6. 聆聽者
偵聽器在後處理器之後運作。我們將使用它向檔案系統寫入一份報告。首先,讓我們寫一個輔助函數並設定一些變數:
println(writer, message, arg1) {
writer.println(String.format(message, new Object[] {arg1}));
}
thread = ctx.getThread();
threadGroup = ctx.getThreadGroup();
request = prev.getResponseDataAsString();
response = prev.getResponseMessage();
ctx
變數提供來自線程組和當前線程的資訊。接下來,讓我們建立一個FileWriter
以在主目錄中寫入報告:
fw = new FileWriter(new File(System.getProperty("user.home"), "jmeter-report.txt"), true);
writer = new PrintWriter(new BufferedWriter(fw));
println(writer, "* iteration: %s", vars.getIteration());
println(writer, "* elapsed time: %s ms.", prev.getTime());
println(writer, "* request: %s", request);
println(writer, "= %s bytes", prev.getBytesAsLong());
println(writer, "* response body: %s", response);
println(writer, "= %s bytes", response.getBytes().length);
由於它針對每個執行緒迭代運行,因此我們呼叫vars.getIteration()
來追蹤迭代計數。最後,如果目前迭代是summary-iterations
的倍數,我們列印一個摘要:
if (vars.getIteration() % vars.getObject("summary-iterations") == 0) {
println(writer, "## summary for %s", thread.getThreadName());
println(writer, "* total bytes sent: %s bytes", vars.get("bytes-sent-total"));
println(writer, "* total bytes received: %s bytes", vars.get("bytes-received-total"));
println(writer, "* total elapsed time: %s ms.", vars.get("elapsed-time-total"));
}
最後,讓我們關閉writer
:
writer.close();
七、結論
在本文中,我們探討如何有效地使用 JMeter 中的 BeanShell 為測試計劃添加自訂腳本。我們介紹了預處理器、採樣器、後處理器和監聽器等重要元件,展示如何操作請求資料、處理回應和記錄指標。
與往常一樣,原始碼可以在 GitHub 上取得。