1.簡介
在效能測試中為了真實模擬使用者請求,往往我們需要讓提交的表單內容每次都發生變化,這個過程叫做引數化。JMeter配置元件與前置處理器都能幫助我們進行引數化,但是都有侷限性,為了幫助我們能夠更好地進行引數化,JMeter提供了一組函式來幫助我們引數化生成需要的資料,這些函式可以函式助手皮膚來進行編輯。當然函式助手的功能不僅僅是做引數化,還能幫助我們運算、字元編碼格式轉換、獲取執行時引數等功能。下面巨集哥介紹和分享一下函式助手中的函式。
JMeter提供了很多函式,如果能夠熟練使用,可以為指令碼帶來很多方便。可以很方便的實現一些小功能,幾乎可以用於測試計劃中的任何元件。
JMeter函式是一種特殊值,可用於除測試計劃外的任何元件。
函式呼叫的格式如下所示:
${__functionName(var1,var2,var3)}
其中,“__”是兩個英文半形的下劃線,functionName為函式名,括號內是函式的引數,無引數時可以不用括號,如${__UUID},其中引數視不同函式而定。
Tips:
如果引數包含逗號,那麼一定要使用“\”來轉義,否則JMeter會把它當作一個引數分隔符
實際使用時,可通過函式助手對話方塊選擇函式,設定引數後,點選生成按鈕生成函式字串。
2.JMeter 中的常用函式主要分為如下幾類
函式型別 | 函式名稱 | 函式作用 | 啟用版本 |
---|---|---|---|
指令碼函式
|
__BeanShell |
執行 beanshell 指令碼 | 1.X |
__javaScript |
執行 js 指令碼 | 1.9 | |
字串操作函式
|
__split |
根據分隔符拆分字串為多個變數 | 2.0.2 |
__changeCase |
轉換大小寫 | 4.0 | |
__regexFunction |
使用正規表示式解析之前的響應結果 | 1.X | |
屬性資訊函式
|
__isPropDefined |
判斷屬性是否存在 | 4.0 |
__property |
對多個整數求和 | 1.8.1 | |
__P |
簡化的屬性函式,用於與命令列上定義的屬性一起使用 | 2.0 | |
__setProperty |
簡化的屬性函式,用於與命令列上定義的屬性一起使用 | 2.0 | |
資料輸入函式
|
__StringFromFile |
從文字檔案中讀取字串,每次呼叫讀取一行 | 1.9 |
__FileToString |
把檔案讀取成一個字串,每次呼叫都是讀取整個檔案 | 2.4 | |
__CSVRead |
返回當前正在執行的執行緒的編號 | 1.9 | |
__XPath |
使用 XPath 語法匹配 XML檔案 | 2.0 | |
資料計算函式
|
__counter |
計數器函式 | 1.9 |
__intSum |
對多個整數求和 | 1.8.1 | |
__longSum |
長整型求和 | 2.3.2 | |
__Random |
返回指定最大值和最小值之間的隨機整數 | 1.9 | |
__RandomDate |
返回給定開始日期和結束日期值之間的隨機日期 | 3.3 | |
_RandomString |
根據給定的字元生成指定長度的隨機字串 | 2.6 | |
__UUID |
通用唯一識別符號函式 | 2.9 | |
獲取資訊函式
|
__TestPlanName |
返回當前測試計劃的名稱 | |
__threadGroupName |
返回當前執行緒組的名稱 | 4.1 | |
__threadNum |
返回當前正在執行的執行緒的編號 | 1.X | |
__samplerName |
返回當前請求的名稱 | 2.5 | |
__log |
輸出日誌資訊 | 2.2 | |
__time |
以多種格式返回當前時間 | 2.2 |
2.1 指令碼函式
2.1.1__BeanShell函式
JMeter支援BeanShell指令碼語言,JMeter函式助手中提供BeanShell函式支援,__BeanShell函式入參可以是BeanShell語法的程式語句或者BeanShell指令碼檔案。調出函式皮膚,我們在“值”中輸入的是兩個字串相加,然後點選“生成”按鈕,就會生成一串以$開頭的表示式,表示式在請求(Sampler)中可以直接呼叫。
1、我們先來看看這個__BeanShell 長得是啥樣子,路徑:函式助手 > 選擇__BeanShell ,如下圖所示:
2、關鍵引數說明:
它有兩個引數,第一個引數是要執行的語句,可以是beanshell語句或者是檔案地址,是必選引數;第二個引數是儲存結果的變數名稱,非必選引數。
3、例項
1.${__BeanShell(123456*789)}:返回97406784,如下圖所示:
2.${__BeanShell(source("function.bsh"))}:會執行外部指令碼function.bsh,並返回結果,如下圖所示:
檔案裡程式碼:System.out.print("bjhg");
返回結果:
3.${__BeanShell(import java.util.*;Properties props = System.getProperties();String osName = props.getProperty("os.name");if(osName.contains("Windows"))return 443;return 8443;)}:判斷Windows返回埠443
import java.util.*; Properties props = System.getProperties(); String osName = props.getProperty("os.name"); if(osName.contains("Windows")) return 443; return 8443;
4、與beanshell元件比較:
該函式與beanshell元件(beanshell sampler、beanshell preprocess等)作用是一樣的,只是beanshell函式更常用於一些簡單的判斷或計算等,可以把少量的指令碼放在函式中直接賦值給一個變數,而不用總是新增beanshell元件。
2.1.2__javaScript
用來執行 JavaScript
指令碼片段,並返回結果值。
該函式會呼叫標準的 JavaScript 直譯器,還可以直接呼叫 jmeter 的內建函式。
注意:文字字串要新增必要的引號。如果表示式中有逗號,要確保對其轉義。
例如:${__javaScript('${sp}'.slice(7\,99999))}
,對 7 之後的逗號進行了轉義。
1、我們先來看看這個__javaScript
長得是啥樣子,路徑:函式助手 > 選擇__javaScript
,如下圖所示:
2、關鍵引數說明:
第一個引數:JavaScript程式碼片段,待執行的JavaScript程式碼片段。例如:
1.new Date():返回當前日期和時間
2. Math.floor(Math.random()*(${maxRandom},+1)):在0 和變數maxRandom之間的隨機數
3.${minRandom}+Math.floor(Math.random()*(${maxRandom}-${minRandom}+1)):在變數 minRandom和maxRandom之間的隨機數"${VAR}"=="abcd"
第二個引數:變數名,重用函式計算值的引用名
請記得為文字字串新增必要的引號。另外,如果表示式中有逗號,請確保對其轉義。例如,${__javaScript('${sp}'.slice(7\,99999))},對7之後的逗號進行了轉義。
3、例項
2.2字串操作函式
2.2.1__split
根據分隔符拆分字串為多個變數。
當兩個分隔符中間沒有字元時,返回 ?
。
被拆分出來的字串,儲存在變數中,類似這樣:${VAR_1}, ${VAR_2} ...
,總個數是 ${VAR_n}
。
如果最後一個字元是分隔符,也會返回 ?
。
函式__split會通過分隔符來拆分傳遞給它的字串,並返回原始的字串。如果分隔符緊挨在一起,那麼函式就會以變數值的形式返回"?"。
拆分出來的字串,以變數${VAR_1}、{VAR_2}…以此類推的形式加以返回。JMeter 2.1.2及其以後版本,拖尾的分隔符會被認為缺少一個變數,會返回"?"。
另外,為了更好地配合ForEach控制器,現在__split會刪除第一個不用的變數(由前一次分隔符所設定)。
1、我們先來看看這個__split
長得是啥樣子,路徑:函式助手 > 選擇__split
,如下圖所示:
2、關鍵引數說明:
待拆分字串 |
一個待拆分字串,例如“a|b|c” |
是 |
變數名 |
重用函式計算值的引用名 |
否 |
分隔符 |
分隔符,例如“|”。如果省略了此引數,函式會使用逗號做分隔符。需要注意的是,假如 要多此一舉,明確指定使用逗號,需要對逗號轉義,如“\,” |
否 |
3、示例:
定義字串:
VAR="a||c|"
呼叫 split 函式:
${__split(${VAR},VAR,|)}
返回 "a||c|",並生成如下變數:
VAR_n=4
VAR_1=a
VAR_2=?
VAR_3=c
VAR_4=?
VAR_5=null
2.2.2__changeCase
根據指定的模式,修改字串大小寫;
可選模式有:UPPER
、LOWER
、CAPITALIZE
。
1、我們先來看看這個__changeCase
長得是啥樣子,路徑:函式助手 > 選擇__changeCase
,如下圖所示:
2、關鍵引數說明:
第一個引數:需要修改的字串
第二個引數:對字串作用的模式3種
第三個引數:字串修改後,儲存的變數名,賦值的變數名
3、示例:
(1)UPPER--轉換成大寫字母: ${__changeCase(Avaro omnia desunt\, inopi pauca\, sapienti nihil,UPPER,)} 返回 AVARO OMNIA DESUNT, INOPI PAUCA, SAPIENTI NIHIL
(2)LOWER--轉換成小寫字母: ${__changeCase(LABOR OMNIA VINCIT IMPROBUS,LOWER,)} 返回 labor omnia vincit improbus
(3)CAPITALIZE--單詞首字母大寫: ${__changeCase(omnibus viis romam pervenitur,CAPITALIZE,)} 返回 Omnibus viis romam pervenitur
2.2.3__regexFunction
使用正規表示式解析之前的響應結果。
1、我們先來看看這個__regexFunction
長得是啥樣子,路徑:函式助手 > 選擇__
,如下圖所示:regexFunction
該函式使用使用者提供的正規表示式來解析前面的伺服器響應(或者是某個變數值)。函式會返回一個有模板的字串,其中攜帶有可變的值。
在函式的第6個引數中,可以指定一個引用名,儲存變數值,供後續呼叫。__regexFunction還可以被用來儲存值,以便供後續使用。在函式的第6個引數中,測試人員可以指定一個引用名。在函式執行以後,測試人員可以使用使用者定義值的語法來獲取同樣的值。例如,如果測試人員輸入"refName"作為第6個引數,那麼測試人員可以使用
變數呼叫示例:
Name of variable in which to store the result
:在這個引數中設定變數名為 refName
,那麼我們可以使用:
${refName}來引用第2個引數(Template for the replacement string)的計算結果,這依賴於函式的解析結果。
${refName_g0}來引用函式解析後發現的所有匹配結果。
${refName_g1}來引用函式解析後發現的第一個匹配組合。
${refName_g#}來引用函式解析後發現的第n個匹配組合。
${refName_matchNr}來引用函式總共發現的匹配組合數目。
2、具體引數描述如下:
函式引數 |
描述 |
是否必需 |
第1個引數 |
第1個引數是用於解析伺服器響應資料的正規表示式,它會找到所有匹配項;如果希望將表示式中的 某部分應用在模板字串中,一定記得為其加上圓括號。例如,<a href="(.*)">,這樣就會將鏈 接的值存放到第一個匹配組合中(這裡只有一個匹配組合)。又如,<input type="hidden" name="(.*)"value="(.*)">,在這個例子中,連結的name作為第一個匹配組合,連結的value會 作為第二個匹配組合,這些組合可以用在測試人員的模板字串中。 |
是 |
第2個引數 |
這是一個模板字串,函式會動態填寫字串的部分內容。要在字串中引用正規表示式捕獲的匹配組 合,請使用語法:[groupnumber][groupnumber]。例如11或者 22,模板可以是任何字串。 |
是 |
第3個引數 |
第3個引數告訴JMeter使用第幾次匹配;測試人員的正規表示式可能會找到多個匹配項,對此, 有4種選擇: n 整數,直接告訴JMeter使用第幾個匹配項; n “1”對應第一個匹配,“2”對應第二個匹配,以此類推; n RAND,告訴JMeter隨機選擇一個匹配項; n ALL,告訴JMeter使用所有匹配項,為每個匹配項建立一個模板字串,並將它們連線在一起 n 浮點值0到1之間,根據公式(找到的總匹配數目*指定浮點值)計算使用第幾個匹配項,計算值 向最近的整數取整 |
否,預設值為1 |
第4個引數 |
如果在上一個引數中選擇了“ALL”,那麼這第4個引數會被插入到重複的模板值之間 |
否 |
第5個引數 |
如果沒有找到匹配項返回的預設值 |
否 |
第6個引數 |
重用函式解析值的引用名,參見上面內容 |
否 |
第7個引數 |
輸入變數名稱。如果指定了這一引數,那麼該變數的值就會作為函式的輸入,而不再使用前面的取樣結 果作為搜尋物件 |
否 |
其實這個函式的作用跟正規表示式提取器的作用是類似的。
2.3屬性資訊函式
2.3.1__isPropDefined
用於判斷屬性是否存在。
1、我們先來看看這個__isPropDefined
長得是啥樣子,路徑:函式助手 > 選擇__
,如下圖所示:isPropDefined
2、關鍵引數說明:
Name of property:屬性名稱
3、示例:
${__isPropDefined(START.HMS)}
判斷屬性 START.HMS 是否存在,返回 true。
2.3.2__property
獲取屬性值。獲取Jmeter的屬性,%JMETER_HOME%\bin\jmeter.properties
1、我們先來看看這個__property
長得是啥樣子,路徑:函式助手 > 選擇__
,如下圖所示:property
2、關鍵引數說明:
Name of property:屬性名稱;
Name of variable in which to store the result (optional):變數名;
default Value:預設值
3、示例:
${__property(user.dir)} 返回 user.dir 的值。
${__property(user.dir,UDIR)} 返回 user.dir 的值,並儲存在變數 UDIR 中。
${__property(abcd,ABCD,atod)} 返回屬性 abcd 的值,如果該屬性未定義則返回 atod,並儲存在變數 ABCD 中。
${__property(abcd,,atod)} 返回屬性 abcd 的值,如果該屬性未定義則返回 atod,不儲存結果值。
${__property(log_level.jmeter,log_Level,)}
2.3.3__P
這是一個簡化的屬性函式,用於與命令列上定義的屬性一起使用。獲取命令列中定義的屬性,非GUI方式執行測試計劃時這個函式可用來做引數化,由執行命令動態指定引數值,方便與Jenkins等整合完成效能測試工作
與_property
函式不同,沒有選項可以將值儲存在變數中,如果不提供預設值,則假定為1。
1、我們先來看看這個__P
長得是啥樣子,路徑:函式助手 > 選擇__P
,如下圖所示:
2、關鍵引數說明:
Name of property:屬性名稱;
default Value:預設值
3、示例:
在指令碼中定義如下兩個函式:
${__P(group1.threads, 10)}
${__P(group1.loops)}
在命令列中呼叫:
jmeter -Jgroup1.threads=50 -Jgroup1.loops=100 執行時,兩個引數分別是 50、100。
若命令列中不設定屬性,執行時,兩個引數分別是 10、1。
2.3.4__setProperty
該函式用於設定 JMeter 屬性的值。
函式的預設返回值是空字串,因此該函式可以被用在任何地方,只要對函式本身呼叫是正確的。
1、我們先來看看這個__setProperty
長得是啥樣子,路徑:函式助手 > 選擇__
,如下圖所示:setProperty
通過將函式可選的第3個引數設定為"true",函式就會返回屬性的原始值。
屬性對於JMeter是全域性的,因此可以被用來線上程和執行緒組之間通訊。
2、關鍵引數說明:
Name of property:屬性名稱;
Value of property:屬性值;
Return Original Value of property (default false)?:是否返回函式結果
3、例項
${__setProperty(log_level.jmeter,Debug,true)}
2.4資料輸入函式
2.4.2__StringFromFile
從檔案中讀取內容,一行一行的讀取,讀完再從頭開始。
1、我們先來看看這個__StringFromFile
長得是啥樣子,路徑:函式助手 > 選擇__
,如下圖所示:StringFromFile
作用
用於從文字檔案中讀取字串,每次讀取一行,支援讀取多個檔案。
使用配置元件CSV Data Set Config ,也能達到相同的目的,而且方法更簡單,但是它目前不支援多個輸入檔案。
每次呼叫函式,都會從檔案中讀取下一行。當到達檔案末尾時,函式又會從檔案開始處重新讀取,直到最大迴圈次數。如果在一個測試指令碼中對該函式有多次引用,那麼每一次引用都會獨立開啟檔案,即使檔名是相同的(如果函式讀取的值,在指令碼其他地方也有使用,那麼就需要為每一次函式呼叫指定不同的變數名)。
如果在開啟或者讀取檔案時發生錯誤,那麼函式就會返回字串 **ERR**
。
2、 引數
引數 | 描述 | 是否必填 |
---|---|---|
檔名 | 檔名的路徑 (路徑可以相對於 JMeter 啟動目錄)。 如果使用序列號,路徑名稱應該適合傳遞到 DecimalFormat。 |
是 |
變數名 | 用於後續呼叫該函式的變數名稱 | 否 |
啟動序號 | 初始序列號(如果省略,則將結束序列號視為迴圈計數) | 否 |
末端序號 | 最終序列號(如果省略,序列號可以無限制地增加) | 否 |
啟動序號:初始的序列號,如果省略,那麼結束序列號就代表檔案的迴圈讀取次數。
末端序號:結束序列號,如果省略,那麼序列號會無限增長。
3、示例
讀取單個檔案:
${_StringFromFile(test.txt,,,)} 讀取test.txt
讀取多個檔案,需要在檔名中使用序列號:
${_StringFromFile(PIN.DAT,,,2)} 讀取 PIN.DAT 兩次
${_StringFromFile(PIN#'.'DAT,,1,3)} 讀取 PIN1.DAT PIN2.DAT PIN3.DAT
${_StringFromFile(pin000'.'dat,,6,8)} 讀取 pin006.dat pin007.dat pin008.dat
使用序列號時,路徑名被用作 java.text.DecimalFormat
的格式字串。當前序列號作為唯一引數傳入。如果未指定開始序列號,則按原樣使用路徑名稱。
4、格式化序列
常用的兩個格式化序列:
#
:插入數字,沒有前導零或空格。000
:插入數字,數字不足三位時,將插入前導零補足三位;數字超過三位時,則插入數字實際位數。
用法說明:
在不帶前導零的情況下插入數字:
pin#'.'dat -> pin1.dat, ... pin9.dat, pin10.dat, ... pin9999.dat
帶前導零的情況下插入數字:
pin000'.'dat -> pin001.dat ... pin099.dat ... pin999.dat ... pin9999.dat
在不帶前導零的情況下追加數字:
pin'.'dat# -> pin.dat1, ... pin.dat9 ... pin.dat999
注意:上面的 .
是格式化字元,必須用單引號括起來。
2.4.2__FileToString
把檔案讀取成一個字串,每次呼叫都是讀取整個檔案。讀取檔案儲存至變數中。
如果出現開啟或讀取檔案的錯誤,則函式將返回字串 **ERR**
。
1、我們先來看看這個__FileToString
長得是啥樣子,路徑:函式助手 > 選擇__
,如下圖所示:FileToString
2、關鍵引數說明:
引數 | 描述 | 是否必填 |
---|---|---|
檔名 | 檔名的路徑。(路徑可以相對於JMeter啟動目錄) | 是 |
檔案編碼 | 用於讀取檔案的編碼。如果未指定,則使用平臺預設值。 | 否 |
變數名 | 用於後續呼叫該函式的變數名稱。 | 否 |
3、例項
${__FileToString(C:\Users\DELL\Desktop\user_info.csv,utf-8,user_info)}
讀取結果可能會出現中文亂碼,注意把檔案修改成UTF-8的編碼格式儲存。
2.4.3__CSVRead
從檔案讀取指定列的值(讀取固定值/讀取動態值/使用檔案別名)
1、我們先來看看這個__CSVRead
長得是啥樣子,路徑:函式助手 > 選擇__CSVRead
,如下圖所示:
作用
- 從一個 CSV 檔案中返回一個字串,支援多個檔名。
- 當第一次呼叫該函式時,檔案將被開啟並讀取到一個內部陣列中。如果檢測到空行,這將被視為檔案的末尾。
- 所有對同一檔名的後續引用都使用相同的內部陣列,檔名區分大小寫。
- 每個執行緒都有自己的指向檔案陣列中當前行的內部指標。當執行緒首先引用檔案時,它將在陣列中分配下一個空閒行,因此每個執行緒將訪問與所有其他執行緒不同的行(除非陣列中的執行緒多於行)。
2、引數
引數 | 描述 | 是否必填 |
---|---|---|
檔名 | 要讀取的檔名 | 是 |
列號 | 檔案中的列號。0–第一列,1–第二列,next–檔案的下一行。 | 是 |
3、示例
讀取檔案中的第1行第1列: ${__CSVRead(random.txt,0)} 讀取檔案中的第1行第2列,並進入檔案下一行: ${__CSVRead(random.txt,1)}${__CSVRead(random.txt,next)} 讀取檔案第2行第1列: ${__CSVRead(random.txt,0)} 讀取檔案中的第2行第2列,並進入檔案下一行: ${__CSVRead(random.txt,1)}${__CSVRead(random.txt,next)}
讀取檔案可能會出現中文亂碼,修改檔案的編碼為:ANSI編碼格式就可以了。
注意:
- 該函式不適合用於大型檔案,因為整個檔案都儲存在記憶體中。
- 對於較大的檔案,最好使用
CSV Data Set Config
或者StringFromFile
。 - 預設情況下,該函式在每個逗號處拆分行。如果要輸入包含逗號的列,則需要通過設定屬性將分隔符更改為不出現在任何列資料中的字元,修改
jmeter.properties
檔案中的csvread.delimiter=
。
2.4.4__XPath
根據xpath獲取xml節點內容,沒有匹配到,則返回空字串。
1、我們先來看看這個__Xpath
長得是啥樣子,路徑:函式助手 > 選擇__Xpath
,如下圖所示:
2、關鍵引數說明:
XML file to get values from:待解析的xml檔案;
XPath expression to match against :xpath表示式匹配xml節點
注意:
- 該函式讀取 XML 檔案,並在檔案中尋找與指定 XPath 相匹配的地方。
- 每呼叫函式一次,就會返回下一個匹配項。到達檔案末尾後,會從頭開始。如果沒有匹配的節點,那麼函式會返回空字串,另外,還會向JMeter日誌檔案寫一條警告資訊。
- 整個節點列表都會被儲存在記憶體之中,所以檔案較大時不適合使用。
3、示例:
巨集哥找了一個JMeter安裝目錄下的一個build.xml檔案,進行實戰,如下:預設取值1,name=all,修改[2],name=run。
${__XPath(D:\software\apache-jmeter-5.1.1\extras\build.xml,//target[2]/@name)}
這會找到 build.xml 檔案中的所有目標節點,並返回下一個 name 屬性的內容。
3.小結
3.1可直接訪問變數
log:直接呼叫logger函式 ctx:獲取JMeterContent物件 vars:獲取JMeter定義的變數 props:獲取JMeter配置屬性 threadName:獲取Jmeter執行緒名 sampler:獲取Sampler例項 sampleResult:獲取SamplerResult例項 OUT:類似System.out.println, OUT.println()
好了,今天到這裡JMeter5的函式上篇就介紹和分享完了,感謝您耐心的閱讀和一路支援巨集哥!!!