透過 Java 程式建立並執行 Apache JMeter 測試腳本
一、簡介
Apache JMeter是一個基於 Java 的開源應用程序,旨在分析和測量 Web 應用程式的效能。它允許測試人員模擬伺服器、網路或物件上的重負載,以分析不同負載下的整體效能。 JMeter 提供了一個易於使用的 GUI,用於定義、執行和查看各種負載測試的報告。
儘管 JMeter 提供了一個用戶友好的 GUI 來創建和執行測試腳本,但在某些情況下利用 Java 程式設計進行自動化可能會很有用,特別是在持續整合和部署管道中。
在本教程中,我們將探討如何使用 Java 以程式設計方式建立和執行 Apache JMeter 測試腳本,並透過一個實際範例來說明所涉及的步驟。
2.搭建環境
在開始編碼之前,讓我們確保已經設定了所需的環境。要安裝JMeter,我們可以從JMeter網站下載它。 JMeter 與 Java 8 或更高版本相容。或者,在 macOS 上,我們可以透過以下指令使用 Homebrew 安裝 JMeter:
brew install jmeter
我們還需要配置 Java 專案以包含 JMeter 屬性。對於 Maven 項目,將以下依賴項新增至我們的pom.xml
檔案中:
<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_core</artifactId>
<version>5.6.3</version>
</dependency>
<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_http</artifactId>
<version>5.6.3</version>
</dependency>
這些依賴項包括Apache JMeter 的核心功能和HTTP 元件。它們提供了用於建立和運行 JMeter 測試計劃、發送 HTTP 請求以及在 JMeter 測試計劃中處理 HTTP 回應的基本類別和實用程式。
3. 建立測試腳本和環境變數文件
我們將產生一個簡單的測試腳本來模擬對指定 URL 或應用程式的 HTTP GET 請求。該腳本的主要目的是對指定的目標應用程式執行負載測試,在本例中為https://www.google.com
。
它將透過分派多個並發請求來模擬所提供 URL 上的真實負載,使我們能夠評估應用程式在不同負載層級的效能。在下面的腳本中,我們首先檢查JMETER_HOME
環境變數以找到 JMeter 安裝目錄。
驗證後,我們初始化 JMeter 引擎StandardJMeterEngine
並建立測試計畫TestPlan.
以下是實現此目的的 Java 程式碼:
@Test
void givenJMeterScript_whenUsingCode_thenExecuteViaJavaProgram() throws IOException {
String jmeterHome = System.getenv("JMETER_HOME");
if (jmeterHome == null) {
throw new RuntimeException("JMETER_HOME environment variable is not set.");
}
String file = Objects.requireNonNull(JMeterLiveTest.class.getClassLoader().getResource("jmeter.properties")).getFile();
JMeterUtils.setJMeterHome(jmeterHome);
JMeterUtils.loadJMeterProperties(file);
JMeterUtils.initLocale();
StandardJMeterEngine jmeter = new StandardJMeterEngine();
HTTPSamplerProxy httpSampler = getHttpSamplerProxy();
LoopController loopController = getLoopController();
ThreadGroup threadGroup = getThreadGroup(loopController);
TestPlan testPlan = getTestPlan(threadGroup);
HashTree testPlanTree = new HashTree();
HashTree threadGroupHashTree = testPlanTree.add(testPlan, threadGroup);
threadGroupHashTree.add(httpSampler);
SaveService.saveTree(testPlanTree, Files.newOutputStream(Paths.get("script.jmx")));
Summariser summer = null;
String summariserName = JMeterUtils.getPropDefault("summariser.name", "summary");
if (summariserName.length() > 0) {
summer = new Summariser(summariserName);
}
String logFile = "output-logs.jtl";
ResultCollector logger = new ResultCollector(summer);
logger.setFilename(logFile);
testPlanTree.add(testPlanTree.getArray()[0], logger);
jmeter.configure(testPlanTree);
jmeter.run();
System.out.println("Test completed. See output-logs.jtl file for results");
System.out.println("JMeter .jmx script is available at script.jmx");
}
在下面的getLoopController()
方法中,循環控制器指示迭代或循環的數量。在這種情況下,我們將循環控制器配置為僅執行測試計劃一次:
private static LoopController getLoopController() {
LoopController loopController = new LoopController();
loopController.setLoops(1);
loopController.setFirst(true);
loopController.setProperty(TestElement.TEST_CLASS, LoopController.class.getName());
loopController.setProperty(TestElement.GUI_CLASS, LoopControlPanel.class.getName());
loopController.initialize();
return loopController;
}
getThreadGroup()
方法定義了一個名為「 Sample Thread Group
」的執行緒群組,指定虛擬使用者/執行緒的數量來模擬啟動週期。該群組中的每個執行緒代表一個向目標 URL 發出請求的虛擬使用者。 「 Sample Thread Group
」包含 10 個執行緒(虛擬使用者),並以 5 秒的間隔逐漸增加:
private static ThreadGroup getThreadGroup(LoopController loopController) {
ThreadGroup threadGroup = new ThreadGroup();
threadGroup.setName("Sample Thread Group");
threadGroup.setNumThreads(10);
threadGroup.setRampUp(5);
threadGroup.setSamplerController(loopController);
threadGroup.setProperty(TestElement.TEST_CLASS, ThreadGroup.class.getName());
threadGroup.setProperty(TestElement.GUI_CLASS, ThreadGroupGui.class.getName());
return threadGroup;
}
隨後,在getHttpSamplerProxy()
方法中,我們建立一個 HTTP 採樣器HTTPSamplerProxy
以將 HTTP GET 請求分派到目標 URL (https://www.google.com)。我們使用網域、路徑和請求方法來配置採樣器:
private static HTTPSamplerProxy getHttpSamplerProxy() {
HTTPSamplerProxy httpSampler = new HTTPSamplerProxy();
httpSampler.setDomain("www.google.com");
httpSampler.setPort(80);
httpSampler.setPath("/");
httpSampler.setMethod("GET");
httpSampler.setProperty(TestElement.TEST_CLASS, HTTPSamplerProxy.class.getName());
httpSampler.setProperty(TestElement.GUI_CLASS, HttpTestSampleGui.class.getName());
return httpSampler;
}
我們透過將執行緒組和 HTTP 採樣器新增至HashTree:
private static TestPlan getTestPlan(ThreadGroup threadGroup) {
TestPlan testPlan = new TestPlan("Sample Test Plan");
testPlan.setProperty(TestElement.TEST_CLASS, TestPlan.class.getName());
testPlan.setProperty(TestElement.GUI_CLASS, TestPlanGui.class.getName());
testPlan.addThreadGroup(threadGroup);
return testPlan;
}
最後,我們使用測試計劃樹來設定 JMeter 引擎,並呼叫 run 方法執行測試。
此腳本概述了一個負載配置文件,該配置文件模擬 10 個並髮用戶在 5 秒內逐漸增加。每個使用者都會向目標 URL 發起單一 HTTP GET 請求。由於多次迭代沒有額外的配置,因此負載保持一致。
jmeter.properties
檔案用作 Apache JMeter 用來定義測試執行的各種設定和參數的設定檔。在此文件中,下列屬性指定完成測試執行後儲存測試結果的格式:
jmeter.save.saveservice.output_format=xml
4. 了解輸出文件
我們已將測試計劃儲存為script.jmx
,採用 .jmx 檔案格式,該格式與 JMeter GUI 中的載入和執行相容。此外,我們配置了一個Summarizer
來收集和總結測試結果。此外,還建立了一個結果收集器,將結果儲存在名為output-logs.jtl.
4.1.了解 . jtl
文件
output-logs.jtl
檔案內容如下:
<?xml version="1.0" encoding="UTF-8"?>
<testResults version="1.2">
<httpSample t="354" it="0" lt="340" ct="37" ts="1711874302012" s="true" lb="" rc="200" rm="OK"<br /> tn="Sample Thread Group 1-1" dt="text" by="22388" sby="111" ng="1" na="1">
<java.net.URL>http://www.google.com/</java.net.URL>
</httpSample>
<httpSample t="351" it="0" lt="317" ct="21" ts="1711874302466" s="true" lb="" rc="200" rm="OK"<br /> tn="Sample Thread Group 1-2" dt="text" by="22343" sby="111" ng="1" na="1">
<java.net.URL>http://www.google.com/</java.net.URL>
</httpSample>
<httpSample t="410" it="0" lt="366" ct="14" ts="1711874303024" s="true" lb="" rc="200" rm="OK"<br /> tn="Sample Thread Group 1-3" dt="text" by="22398" sby="111" ng="1" na="1">
<java.net.URL>http://www.google.com/</java.net.URL>
</httpSample>
<httpSample t="363" it="0" lt="344" ct="19" ts="1711874303483" s="true" lb="" rc="200" rm="OK"<br /> tn="Sample Thread Group 1-4" dt="text" by="22367" sby="111" ng="1" na="1">
<java.net.URL>http://www.google.com/</java.net.URL>
</httpSample>
</testResults>
輸出包含表示測試期間發出的 HTTP 請求的<httpSample>
元素,並且包含與該請求相關的各種屬性和元資料。讓我們分解一下這些屬性:
-
t
– 樣本執行所需的總時間(以毫秒為單位) -
it
– 空閒時間,即等待回應的時間 -
lt
– 延遲,即請求到達伺服器並返回所花費的時間,不包括空閒時間 -
ct
– 連線時間,即與伺服器建立連線所花費的時間 -
ts
– 執行樣本時的時間戳,以自紀元以來的毫秒數表示 -
s
– 表示樣本是否成功(true)
或失敗(false)
-
lb
– 與樣本相關的標籤,通常是取樣器名稱 -
rc
– 伺服器傳回的HTTP回應碼 -
rm
– 與回應代碼關聯的回應訊息 -
tn
– 執行範例的執行緒的名稱 -
dt
– 樣本傳回的資料類型(例如文字、二進位) -
by
– 回應正文中收到的位元組數 -
sby
– 請求中發送的位元組數 -
ng/na
– 線程組/所有線程組中的活動線程數
這些數據對於分析測試中的系統效能、識別瓶頸和優化應用程式的效能至關重要。
4.2.了解 . jmx
文件
.jmx 檔案表示 XML 格式的 JMeter 測試計劃配置。 script.jmx
檔案內容如下:
<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="5.0" jmeter="5.4.1">
<org.apache.jorphan.collections.HashTree>
<TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Sample Test Plan"/>
<org.apache.jorphan.collections.HashTree>
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Sample Thread Group">
<intProp name="ThreadGroup.num_threads">10</intProp>
<intProp name="ThreadGroup.ramp_time">5</intProp>
<elementProp name="ThreadGroup.main_controller" elementType="LoopController"<br /> guiclass="LoopControlPanel" testclass="LoopController">
<boolProp name="LoopController.continue_forever">false</boolProp>
<intProp name="LoopController.loops">1</intProp>
</elementProp>
</ThreadGroup>
<org.apache.jorphan.collections.HashTree>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain">www.google.com</stringProp>
<intProp name="HTTPSampler.port">80</intProp>
<stringProp name="HTTPSampler.path">/</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
</HTTPSamplerProxy>
<org.apache.jorphan.collections.HashTree/>
</org.apache.jorphan.collections.HashTree>
</org.apache.jorphan.collections.HashTree>
</org.apache.jorphan.collections.HashTree>
</jmeterTestPlan>
測試計劃在<jmeterTestPlan>
元素中定義。在測試計畫中, <ThreadGroup>
元素描述將執行測試場景的虛擬使用者或執行緒群組。這包括線程數量和啟動時間等詳細資訊。
執行緒組由控制器編排,例如<LoopController>
元素,它管理執行流程,確定循環數以及是否應無限期地繼續執行。
要傳送的實際 HTTP 請求由<HTTPSampleProxy>
元素表示,每個元素都詳細說明網域、連接埠、路徑和 HTTP 方法等方面。這些元素共同構成了在 JMeter 框架內編排效能測試的全面藍圖。它可以模擬使用者與 Web 伺服器的交互以及隨後對伺服器回應的分析。
5. 結論
在本文中,我們示範如何使用 JMeter Java API 以程式設計方式建立和執行 Apache JMeter 測試腳本。使用這種方法,開發人員可以自動化效能測試並將其無縫整合到他們的開發工作流程中。
它可以實現 Web 應用程式的高效測試,幫助在開發週期的早期識別和解決效能瓶頸。
與往常一樣,本文的源代碼可以在 GitHub 上找到。