JMeter關(guān)聯(lián)之正則表達式提取器
一、 關(guān)聯(lián)的定義
為什么要關(guān)聯(lián)
在客戶端與服務(wù)器通信過程中,多個請求/響應(yīng)間的數(shù)據(jù)會有相互依賴的關(guān)系。比如上一個請求返回的某些響應(yīng)數(shù)據(jù)在后續(xù)的請求中需要用到。
下面是一些典型的例子:
- 比如第一次訪問網(wǎng)站獲取的session id在后續(xù)的請求都會將其傳給網(wǎng)站。
- 服務(wù)器生成token返回給用戶,在后續(xù)的請求中要帶上token。
- 根據(jù)條件查詢某記錄,在查詢結(jié)果集中選擇記錄進行操作(比如刪除)。
- ...
但是有些通信協(xié)議是無狀態(tài)的,不存在上下文相關(guān)性。多個請求/響應(yīng)之間的數(shù)據(jù)不能直接進行傳遞;并且每次服務(wù)器返回的數(shù)據(jù)不是一成不變的,傳遞的數(shù)據(jù)不能通過硬編碼(寫死)保存來解決。
比如上面三種情況都會產(chǎn)生動態(tài)變化的數(shù)據(jù):
- session id的生命周期一般在關(guān)閉瀏覽器時就結(jié)束了,每次打開瀏覽器訪問返回的session id并不相同。
- token也有生命周期,一般也是隨機,無狀態(tài)的。
- 若查詢條件參數(shù)化了或服務(wù)器返回的查詢結(jié)果集改變了,后續(xù)的操作可能會失敗。在這些情況下,可以考慮將服務(wù)器返回的動態(tài)變化的數(shù)據(jù)保存到某個參數(shù)中,需要時再從中取出。
關(guān)聯(lián)原理
舉個例子,看電影,看電影過程有如下步驟:
- 購票
- 驗票
- 觀影
每個步驟可以看做一個請求/響應(yīng)。觀眾相當于客戶端,影院方相當于服務(wù)器。
過程如下圖所示:
觀眾購買的電影票可以看成服務(wù)器返回的響應(yīng)數(shù)據(jù),要驗票通過才能入場觀影。
觀眾購票相當于一個請求,驗票是下一個請求,這需要將上一個請求返回的響應(yīng)數(shù)據(jù)(電影票)放在下一個請求中發(fā)送給服務(wù)器處理。
假設(shè)這部電影非常精彩,想重新再看一次,因為電影票只能使用一次,觀眾必須重新購票,才能驗票通過入場;使用第一次購買的電影票入場肯定會被拒之門外。
為了解決這個問題,可以考慮做如下假設(shè):
每次將購買的電影票放入隨身攜帶的LV錢包,并且在放入之前將使用過的票丟棄,以防止入場時掏錯票;入場的時候,從錢包中取出票來驗票,這樣就萬無一失了。
將電影票放入錢包中,相當于將服務(wù)器返回的數(shù)據(jù)保存起來了,這里錢包就是保存關(guān)聯(lián)數(shù)據(jù)的參數(shù)。
- 關(guān)聯(lián)的定義
將服務(wù)器返回的數(shù)據(jù)包中滿足條件的數(shù)據(jù)保存到一個參數(shù)中的過程。
怎樣將服務(wù)器返回的數(shù)據(jù)保存起啦,JMeter中可以使用后置處理器來處理關(guān)聯(lián)數(shù)據(jù),常見的方法有:
- 正則表達式提取器。
- JSON提取器。
需要關(guān)聯(lián)數(shù)據(jù)的特征
怎樣確定哪些數(shù)據(jù)是需要做關(guān)聯(lián)的,可以從關(guān)聯(lián)數(shù)據(jù)的特征來識別出這些數(shù)據(jù)。關(guān)聯(lián)數(shù)據(jù)有如下三個特征:
- 服務(wù)器返回
需要關(guān)聯(lián)的數(shù)據(jù)一定是從服務(wù)器返回的。
客戶端輸入的數(shù)據(jù)不需要進行關(guān)聯(lián),比如輸入的用戶名與密碼。此特征是必選的。
- 數(shù)據(jù)會再次發(fā)送給服務(wù)器處理
保存上一個請求響應(yīng)的數(shù)據(jù),其目的是為了將其用于下一個請求中,否則保存起來沒有意義。此特征是可選特征,也就是說不再次發(fā)送也是可以保存數(shù)據(jù)進行關(guān)聯(lián)的。
- 數(shù)據(jù)動態(tài)變化
上一個請求響應(yīng)的數(shù)據(jù)若不會動態(tài)變化,完全可以寫死在腳本中,不需要花力氣額外保存再次取出。正是由于每次返回的數(shù)據(jù)動態(tài)變化,我們需要根據(jù)某種規(guī)則將這些動態(tài)變化的數(shù)據(jù)找出來保存,然后會取出實際返回的數(shù)據(jù)。但此特征也是可選的。不動態(tài)變化一樣可以保存進行關(guān)聯(lián),但意義不大。
二、正則表達式介紹
JMeter通過內(nèi)嵌的Apache Jakarta ORO軟件來解析處理正則表達式。
Jakarta-ORO是用于處理文本的一組Java類,是目前功能最全性能最好的正則表達式API之一,它提供兼容Perl5類型的正則表達式。
單行模式與多行模式
元字符
擴展正則表達式
四、 正則表達式提取器
配置項
Apply to:
與響應(yīng)斷言中用法一致,不再贅述。
Field to check:
- Body
Response Body,比如HTTP響應(yīng)報文的實體主體,不包含狀態(tài)行與首部。
- Body(unescaped)
Response Body(轉(zhuǎn)換了轉(zhuǎn)義字符),對HTTP響應(yīng)報文的實體主體中的所有HTML轉(zhuǎn)義字符進行了轉(zhuǎn)義處理。由于轉(zhuǎn)義時沒有參照上下文,在處理時可能會出錯,并且開啟此選項會嚴重影響性能,故不建議使用。
- Body as a Document
通過Apache Tika從各種類型的文檔中提取文本。此選項開啟也會嚴重影響性能,謹慎使用。
- Response Headers
一般用于HTTP請求,HTTP響應(yīng)報文中的首部。
- Request Headers
一般用于HTTP請求,HTTP請求報文中的首部。
- URL
一般用于HTTP請求。HTTP請求報文中的請求URL地址(未開啟重定向功能);若開啟了重定向功能,則包含原始請求中的請求URL地址與重定向后的URL地址。
比如前面訪問新浪的例子,開啟了重定向后,則包括:http://www.sina.com/,http://www.sina.com.cn/和https://www.sina.com.cn/三個URL地址。
- Response code
一般用于HTTP協(xié)議,指的是HTTP響應(yīng)報文中的狀態(tài)碼,比如200、301、404等。
- Response Message
一般用于HTTP協(xié)議,指的是HTTP響應(yīng)報文中的原因短語,比如OK、Moved Permanently、Not Found等。
Name of created variable:
用于存儲結(jié)果的JMeter變量的名稱。
Regular Expression:
用于解析響應(yīng)數(shù)據(jù)的正則表達式。使用正則表達式中的()來捕獲響應(yīng)字符串。
Template($i$ where i is capturing group number,starts at 1):
設(shè)置捕獲到的字符串以怎樣的格式保存到存儲結(jié)果的JMeter變量中。
在此項中,可以用$1$表示引用捕獲組1中的內(nèi)容,$2$表示引用捕獲組2中的內(nèi)容,... ,$n$表示引用捕獲 組n中的內(nèi)容, $0$表示引用正則表達式匹配后的整個字符串。
注意除了使用$n$引用捕獲組的內(nèi)容外,還可以加入需要的字符,將匹配的內(nèi)容按照某種格式保存。
Match No.(0 for Random):
匹配序號。從匹配的結(jié)果中怎樣挑選匹配項。
若正則表達式每個捕獲組有多個匹配項。
則1表示第一個匹配項,2表示第二個匹配項,... ,依次類推;0表示從多個匹配項中隨機選擇一個;-i(i=1,2,3,... ,N,-i即負整數(shù))表示引用所有的匹配項。
Default Value:
如果正則表達式?jīng)]有匹配到內(nèi)容,則保存結(jié)果的JMeter變量將設(shè)置為默認值,這樣會對調(diào)試JMeter測試帶來便利。如果沒有提供默認值,則很難判斷正則表達式是否匹配失敗,或者RE元素是否未處理或者是否使用了錯誤的變量。
但是,如果您有多個設(shè)置相同變量的測試元素,那么如果表達式不匹配,您可能希望保持變量不變。在這種情況下,請在調(diào)試完成后刪除默認值。
Use empty default value:
如果選中該復(fù)選框則默認值為空,則JMeter會將保存結(jié)果的JMeter變量設(shè)置為空字符串。
四、應(yīng)用案例
案例說明
業(yè)務(wù)操作步驟:
- 登錄ECshop后臺管理系統(tǒng)。
- 設(shè)置查詢條件(比如按商品品牌)搜索商品。
- 在返回的查詢結(jié)果集中選擇第一個商品刪除。
這里每一步驟對應(yīng)一個HTTP請求,在第二個請求中每次返回的查詢結(jié)果集不一樣(因為每執(zhí)行一次會刪除一個商品),故向第三個請求傳遞的商品編號參數(shù)不能寫死,需要從第二個請求對應(yīng)的響應(yīng)數(shù)據(jù)中提取出來。
操作步驟
這里對第二個步驟一些細節(jié)進行說明:
在第二個請求返回的響應(yīng)數(shù)據(jù)中觀察:
...
23)\">8<\/span><\/td>\r\n \r\n
href=\"..\/goods.php?id=23\" target=\"_blank\" title=\"\u67e5\u770b\">
src=\"images\/icon_view.gif\" width=\"16\" height=\"16\" border=\"0\"
...
發(fā)現(xiàn)返回的goods_id的左邊界為goods.php?id=,右邊界為\",但考慮到.與?以及\為元字符,故需要轉(zhuǎn)義,則正則表達式可以設(shè)置為:
goods\.php\?id=(\d+)\\"
在刪除商品請求中將提取的商品編號替換寫死的數(shù)據(jù):