原文地址: JMeter best-practices
保持使用最新版本
JMeter被經常推薦用來測試性能,鼓勵用戶使用最新的版本。
確保你要經常去閱讀變更記錄中的新功能和模塊的提升。你不應該再使用3.0之前的版本了
使用正確的線程數
你硬件設備的能力及測試計劃將都會影響你的JMeter可運行的線程數。數量也依賴于你的服務有多快(一個可快速響應的服務可以讓JMeter變更更加給力)。像其它性能測試工具一樣,如果你沒有正確的線程數,你將面對不準備或錯誤結果的Coordinated Omission
問題。如果你需要大數量級的壓力測試,考慮使用分布式模式在多臺機器上運行無GUI的JMeter實例。當使用分布式模式時,結果將被聚合在控制器的結果中,如果使用多個自已的實例,結果文件可以聚合用于持續性分析。對于如何在一個給定的平臺上使用JMeter測試,JavaTest Sampler
可以考慮使用。它不需要任何網絡請求便可返回一些信息在最大的吞吐量。
JMeter有選項用于延遲線程創建直到線程正常啟動,如在其它線程組延遲之后和線程自身的啟動時間。這樣就允許一個非常大數量級的線程數,不需要太多的線程同時并發。
Cookie管理器的位置
可在構建一個Web測試中查看
Authorization管理器的位置
可在構建一個高級Web測試中查看
使用HTTP(S) Test Script Recorder
錄制
關于HTTP(S) Test Script Recorder的細節在建議錄制器中。最重要的事情是,剔除你不感興趣的。比如,不關心在錄制過程中的圖片請求(JMeter可以下載一個頁面中的所有圖片-具體查看HTTP Request)。這些內容將會讓你的測試計劃一團糟糕。大部人都會這樣,有一個擴展對你的所有文件集,如.jsp,.asp,.php,.html
或者其它。這些內容你通過輸入.*\.jsp
在Include Pattern
中引入。
或者,你也可以剔除圖片通過輸入.*\.gif
在Exclude Pattern
中。具體依據你的應用程序,你可以選擇一種更好的方案去執行。你也可以去剔除stylesheets,javascritpt文件和其它文件類型
。測試你的配制來驗證你的錄入內容是你想要的,接著清除內容并且開始刷新頁面。
HTTP(S) Test Script Recorder
期望用于使用Recording Controller
發現HTTP Request
記錄的元素至一個線程組元素中。這樣便于你可以直接將所有的樣例打包至一個控制器下,當然可以再給出一個可描述測試用例的名稱。
現在,執行測試用例的步驟。如果你有無前置步驟的測試用例,使用JMeter來錄制你的操作定義你的測試用例。一旦你完成了一系列特定的操作,保存整個測試用例至一個合適的文件名中。接著,清理記錄開始一個新的測試用例。通過這樣操作,你可以快速記錄大量粗糙的
測試用例。
HTTP(S) Test Script Recorder
最有用的一個特性是你可以通過錄制的樣例來抽象出通用的元素。通過定義自定義的用戶變量在測試計劃級別或在用戶自定義變量元素中,你可以用JMeter自動替換你錄制樣例中的值。比如,如果你測試一個APP
在服務xxx.example.com,你可以定義一個變量server
的值為xxx.example.com,再所有在錄制樣例中的值將會被替換為${server}
匹配時,注意大小寫敏感
如果JMeter沒有錄制到任何請求,檢查你的瀏覽器是否啟用代理設置。如果在JMeter沒有啟動時,瀏覽器可正常使用,那瀏覽器一定是沒有使用代理設置。一些瀏覽器忽略了代理設置localhost
或127.0.0.1
,那么請使用本機名或IP代替。
錯誤unknown_ca
可以是你正試圖錄入HTTPS
,瀏覽器不接收JMeter的代理服務證書。
用戶變量
一些測試計劃中,需要使用不同的值對于不同的用戶/線程。如,你想測試需要每個用戶登錄后的一系列步驟。這個使用JMeter可以很容易實現。
比如:
- 創建一個文件,包含用戶名和密碼且使用逗號分隔。存放到與你的測試計劃在同一文件夾。
- 添加一個
CSV DataSet
的配制元素至你的測試計劃。定義變量名為USER
和PASS
。 - 替換登錄名為${USER}和密碼為${PASS}
CSV DataSet
元素將會為每個線程讀取一新行內容。
減少資源使用
減少資源使用的一些建議:
- 使用無GUI的模式:
jmeter -n -t test.jmx -l test.jtl
- 盡量少使用監聽器
Listener
;如果使用上面的-l
標記,他們均可以被刪除或禁用 - 在壓力測試過程中,不要使用
查看結果樹
或在Table中查看結果
監聽器,僅在腳本調試階段使用即可 - 相比使用大量相似的樣例,在一個循環中使用相同的樣例,并使用變量(CSV DataSet)來實現樣例的不同。[
Include Controller
在此步驟沒有任何用,它在文件中添加所有的測試元素至測試計劃中] - 不要使用功能模式
- 使用
CSV
格式輸出要優于XML
- 僅保存需要的數據
- 盡可能使用少的斷言
- 使用最優的腳本語言(查看
JSR223
部分)
如果你的測試需要大量的數據 - 特別是如果需要隨機化的 - 創建測試數據在可被讀取的CSV文件中。這樣會避免浪費資源在運行時。
BeanShell服務
BeanShell
解釋器有一個很有用的特性 - 當可以用來扮演server
,可被telnet
或http
訪問。
沒有安全性。能連接至端口的任何人都可以發布任何BeanShell命令。這些可以提供無限制的訪問至JMeter程序和目標。
不要啟用服務除非端口被限制訪問,如,被防火墻。
如果你想使用服務,在jmeter.properties
中定義下面內容:
beanshell.server.port=9000
beanshell.server.file=../extras/startup.bsh
在上面的例子中,服務將會被啟動,將會監聽端口9000
和9001
。端口9000
用于http
訪問,端口9001
用于telnet
訪問。startup.bsh
文件將會被服務處理,可被用于定義功能和啟動時的變量。啟動文件定義用于啟動和輸出JMter和系統屬性的方法。這些是你將在JMeter控制臺看到的:
Startup script running
Startup script completed
Session started on port: 9001
有一個樣例腳本(extras/remote.bsh
)你可以用來測試服務。[看看它怎么工作的]
當啟動當在JMeterbin
目錄(調整目錄,如果你在其它位置),輸出會像這樣:
$ java -jar ../lib/bshclient.jar localhost 9000 ../extras/remote.bsh
Connecting to BSH server on localhost:9000
Reading responses from server …
BeanShell 2.0b5 - by Pat Niemeyer (pat@pat.net)
bsh % remote.bsh starting
user.home = C:\Documents and Settings\User
user.dir = D:\eclipseworkspaces\main\JMeter_trunk\bin
log_level.jmeter = INFO
log_level.jorphan = INFO
Setting property 'EXAMPLE' to '0'.
Setting property 'EXAMPLE' to '1'.
Setting property 'EXAMPLE' to '2'.
Setting property 'EXAMPLE' to '3'.
Setting property 'EXAMPLE' to '4'.
Setting property 'EXAMPLE' to '5'.
Setting property 'EXAMPLE' to '6'.
Setting property 'EXAMPLE' to '7'.
Setting property 'EXAMPLE' to '8'.
Setting property 'EXAMPLE' to '9'.
EXAMPLE = 9
remote.bsh ended
bsh % … disconnected from server.
舉個例子,假設你有一個運行時間較長的非GUI運行模式測試,并且你想讓吞吐量在測試過程中不同。測試計劃包括Constant Throughout Timer
定義屬性,如${__P(thoughput)}
。下面的BeanShell
可用于改變測試:
printprop("throughput");
curr = Integer.decode(args[0]); // Start value
inc = Integer.decode(args[1]); // Increment
end = Integer.decode(args[2]); // Final value
secs = Integer.decode(args[3]); // Wait between changes
while(curr <= end) {
setprop("throughput",curr.toString()); // Needs to be a string here
Thread.sleep(secs*1000);
curr += inc;
}
printprop("throughput");
腳本可以被存儲在一個文件中(如,throughput.bsh
),使用bshclient.jar
發送至服務。參考:
java -jar ../lib/bshclient.jar localhost 9000 throughput.bsh 70 5 100 60
BeanShell腳本
概述
每一個BeanShell
測試元素在解釋器中的每個線程中均有自己的副本。如果測試元素被重復調用,如: 在loop
中,那么元素會被解釋器存儲在報文中除非Reset bsh.Interpreter before each call
選項被勾選。對擴展的壓力測試,推薦使用腳本引擎集成了可編譯的JSR223腳本語言,可在JSR223中查看詳情。
一些運行時間較長的測試會導致解釋器使用大量的內存;如果真的要這樣做,嘗試使用reset選項。
你可以測試BeanShell
腳本使用命令行解釋器,不依賴于JMeter:
$ java -cp bsh-xxx.jar[;other jars as needed] bsh.Interpreter file.bsh [parameters]
或
$ java -cp bsh-xxx.jar bsh.Interpreter
bsh% source("file.bsh");
bsh% exit(); // or use EOF key (e.g. ^Z or ^D)
共享變量
變量可以被定義在啟動(安裝)腳本。這些數據將會被存儲在測試元素的報文中,除非你使用reset選項。
腳本也可以讀取JMeter的變量通過使用get()
和put()
方法,如:
vars.get("HOST");
vars.put("MSG","Successful");
get()
和put()
方法僅支持字符串變量,但有getObject()
和putObject()
方法可以處理其它類型。JMeter變量對于線程是局部的,但可以被所有的測試元素使用(不適用于BeanShell)。
如果你需要共享變量在線程間,JMeter的屬性可以使用:
import org.apache.jmeter.util.JMeterUtils;
String value = JMeterUtils.getPropDefault("name","");
JMeterUtils.setProperty("name", "value");
樣例.bshrc
文件包括樣例getprop()
和setprop()
的方法定義。
其它可用于共享變量的方法,使用bsh.shared
共享命名空間。參考:
if (bsh.shared.myObj == void){
// not yet defined, so create it:
myObj = new AnyObject();
}
bsh.shared.myObj.process();
相比在測試元素中創建對象,可通過JMeter的屬性beanshell.init.file
文件配制在啟動時創建。這個僅會執行一次。
使用BeanShell
Javascript
Jexl
腳本開發功能
像功能一樣編寫和測試腳本是很困難的。然而,JMeter有JSR223
,BSF
和BeanShell
可用來嘗試。
創建一個簡單的測試計劃包括JSR223
或BSF
樣例和結果樹監聽器。在樣例板塊編寫腳本,通過運行測試來測試它。如果有很多錯誤,這些結果將會被展示在結果樹中。同時運行腳本的結果將會被展示像返回內容一樣。
一旦腳本調試通過,可以當一個變量被存儲在測試計劃中。腳本的變量可被用于創建功能調用。如,支持一個BeanShell
腳本被存儲在變量RANDOM_NAME
。功能調用可以被編寫為${__BeanShell($RANDOM_NAME)}
。不需要其它的逗號在腳本中,因為在變量值被添加之前,功能調用已經被轉化。
參數化測試
經常對于重復運行一個測試在不同的配制中是很有用的。比如,改變線程數/循環數/改變地址名。
一種方式是在測試計劃中定義變量集,并在測試元素中使用這些變量。比如,一個可以定義變量LOOPS=10
,關聯${LOOPS}
至線程組中。為了運行測試循環20次,只需要調整LOOPS
在測試計劃中的值。
這個會快變得糟糕,如果你想在非GUI模式運行的話。一個解決方案是,定義測試計劃變量在屬性中,如LOOPS=${__P(loop,10)}
。這個使用屬性loops
的值,如果沒找到的話默認為10
。loops
屬性也可被JMeter的控制臺命令定義:
jmeter ... -Jloops=12 ...
如果有大量的屬性在一次變更的話,一種實現方式是使用屬性文件
。屬性文件
可通過使用-q
在命令行模式下傳遞至JMeter。
JSR223
元素
為了擴展壓力測試,推薦的腳本語言是一種腳本引擎實現可編譯接口的腳本語言。Groovy
腳本引擎可編譯。然而,在JMeter 2.13版本無論是BeanShell
還是Javascript
都沒有實現,因此最好不要使用它們來擴展壓力測試。
提醒: BeanShell繼承可編譯接口但還沒有被實現,方法會拋異常。JMeter有一個明確的說明關于這個問題。
當使用JSR223
元素時,經常設置存儲一個值至一個唯一的變量中,如果語言支持它。確保腳本沒有使用變量${varName}
來存儲將會獲取第一個值,將會獲取${varName}
的第一個值。替換使用:
vars.get("varName")
你也可以傳遞他們像參數一樣到腳本中,并且像這樣使用它們。
線程組之間共享變量
變量對于線程是局部的;在一個線程中的一個變量集不能被其它線程讀取。設計就是這樣的。針對變量,可以在測試啟動前進行明確,查看參考化測試。如果值直到測試啟動都不知道,有如下選項:
- 存儲變量在屬性中 - 屬性對于JMter實例是全局的
- 寫變量至文件中,重新讀取他們
- 使用
bsh.shared
命令空間 - 查看共享變量 - 寫自己的Java類
屬性配制管理
當你需要修改JMeter屬性,確保你沒有修改jmeter.properties
文件。替換拷貝屬性從jmter.properties
并修改在user.properties
中的值。
這樣做的話,會很容易合并至下一個JMeter版本。
注意jmeter.properties
文件中經常涉及但被理解“從jmeter.properties拷貝到user.properties你想修改且這樣做的屬性。”
user.properties file supersedes the properties defined in jmeter.properties
過時的元素
建議不要使用過時的元素(被這樣標記在變更記錄和在組件相關),并且合并使用新的元素如果可用的話,或新的方式可以實現相同的事情。
過時的元素被刪除從菜單在版本N
中,但通過修改user.properties
中not_in_menu
中屬性可被啟用,并且從那刪除完整的類名。
請注意過濾時的元素地版本`N`將會被刪除在確定的版本`N+1`中,因此盡早確保你沒有使用。