Jmeter(二十三) - 從入門到精通 - JMeter函式 - 上篇(詳解教程)

巨集哥發表於2020-09-22

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

根據指定的模式,修改字串大小寫;

可選模式有:UPPERLOWERCAPITALIZE

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的函式上篇就介紹和分享完了,感謝您耐心的閱讀和一路支援巨集哥!!!

相關文章