自動化介面測試之Postman(一篇搞定)
Postman自動化介面測試
該篇文章針對已經掌握
Postman
基本用法的讀者,即對介面相關概念有一定了解、已經會使用Postman
進行模擬請求的操作。當前環境:
- Window 7 - 64
- Postman 版本(免費版): Chrome App v5.5.3
不同版本頁面 UI 和部分功能位置會有點不同,不過影響不大。
我們先思考一下,如果需要達到自動化介面測試的效果,那麼我們在基本的模擬請求上還需要做哪些呢?
以下我粗略概括為 3 個問題(歡迎更多補充與建議):
- 如何判斷介面是否請求成功
- 如何進行介面批量、定期測試
- 如何處理依賴介面問題(比如商品下單的介面必須要求先登入)
所以,接下來就主要分為 3 個部分進行介紹,以分別解決這 3 個問題。
介面結果判斷
首先,既然是自動化測試,那麼我們肯定需要工具 (Postman)
或者程式碼能幫我們直接判斷結果是否符合預期。那麼在介面測試上,大體就兩個思路:
- 判斷請求返回的
code
是否符合預期 - 判斷請求返回的內容中是否包含預期的內容(關鍵字)
接下來我們看看如何利用 Postman
來解決上述的問題:
功能區
在 Postman
中相關的功能在非常顯眼的地方,Tests
功能的使用需要我們有一定的程式語言基礎,目前支援的指令碼語言即為 JavaScript
Postman
還為我們提供了一些常用的程式碼模板,在 Tests
面板右邊的 SNIPPETS
功能區中,所以對 JavaScript
不大瞭解問題也不大。程式碼編寫相關將在下文進行具體介紹。
指令碼相關
先看上圖的程式碼部分,我們可以發現 responseCode
、 responseBody
和 tests
三個變數(可直接使用) :
responseCode
:包含請求的返回的狀態資訊(如:code)responseBody
: 為介面請求放回的資料內容(型別為字串)tests
: 為鍵值對形式,用於表示我們的測試結果是成功與否,最終展示在Test Results
中。
- key :(如:code 200)我們可以用來當做結果的一個描述
- value:其值為布林型,
ture
表示測試通過,false
表示測試失敗。
所以上述程式碼應該不難理解了,而有了返回結果的資料以及表示結果成功與否的方式,那麼我們“介面結果判斷”的問題也就基本解決了。
另外還有幾個比較常用的:
responseTime
:請求所耗時長postman
:可以做的比較多,比如
- 獲取返回資料的頭部資訊:
postman.getResponseHeader("")
- 設定全域性變數:
postman.setGlobalVariable("variable_key", "variable_value");
- 獲取返回資料的頭部資訊:
更多功能可以檢視官方文件(需梯子)
程式碼模板
Postman
在 SNIPPETS
功能區中為我們提供的程式碼模板已經能解決大部分情況了,以下先挑幾個跟結果判斷相關的進行講解:
Status code : Code is 200
//根據返回的 Code 判斷請求情況 tests["Status code is 200"] = responseCode.code === 200;
Response body: Contains string
//判斷返回的內容中是否存在“關鍵字”。(tests 的 key 可修改,將不再強調) tests["Body matches string"] = responseBody.has("這裡可以改為你要判斷的關鍵字內容"); //如上文提到的: // 判斷結果中是否存在 access_token 關鍵字 tests["has access_token"] = responseBody.has("access_token");
Response body: is equal to string
//判斷返回內容是否跟預期完全相等。 tests["Body is correct"] = responseBody === "這裡可以改為你的預期內容";
Response body: JSON value check
//上文提到,responseBody 為字串型別,支援轉為 Json 格式 var jsonData = JSON.parse(responseBody); tests["Your test name"] = jsonData.value === 100;
Response time is less than 200ms
//判斷請求時長是否小於200ms ,具體時長按情況自定義 tests["Response time is less than 200ms"] = responseTime < 200;
以上介紹的這些基本已經足夠完成對單一介面的測試了,但我們知道如果沒有批量、定時任務那麼這些都將毫無意義,繼續…
集合(批量)測試
想要進行介面的批量測試、管理,那麼我們需要將待測試的介面全部都儲存到同一個集合(Collections)
中,你可以認為就是儲存到同一個資料夾中。先看看 Postman
中的操作步驟:
通過以上步驟,我們得到一個待測的介面集合,為了簡化情況,我這邊每個介面成功與否的條件都是用 code
是否為 200 來判斷:
tests["Status code is 200"] = responseCode.code === 200;
批量執行
以上裝備就緒後,我們就可以開始批量執行介面進行測試了:
點選Run
後,會新開啟一個頁面:
Environment
:用於切換介面執行的環境,這裡先不管,後面再講Iteration
:用於設定介面一共要執行的次數。這裡我設定了 3 次,可以在右邊的RESULTS
中看出,每個介面都被運行了 3 次。Delay
: 設定每次執行介面之間的時間間隔,單位為毫秒。Data File
: 上傳測試資料檔案 (下文單獨講)
變化的引數資料
我們已經瞭解了,如何讓多個介面迴圈執行多次,但是現在有個問題,按目前這個步驟,每次執行時介面的引數都是一樣的,那麼就算我們執行個100次、1000次意義也不大。
先看看我們寫好的一個登入功能的介面:
使用變數
現在登入的賬號和密碼引數都是寫死的,也就是不過我們執行多少次,都是拿這個賬號去測試。 那麼如果想要測試賬號密碼引數使用其它值有沒有異常怎麼辦呢?( 想要每次都手動改的可以跳過這部分 /手動滑稽)這裡我們先簡單講一下在 Postman
中使用如何“變數”,如下圖:
引用一個變數的語法:{{變數名}}, 圖中可以看到,我們將賬戶和密碼欄位的引數值都設定為變數:{{username}} 、{{password}}
。修改完直接點選執行 (Send)
當然是不行的,因為目前這兩個變數還未被賦值,不過我們可以在 Pre-request Script
面板中進行賦值操作:
Pre-request Script
Pre-request Script
與 Tests
類似,區別在於:Pre-request Script
中的指令碼是在執行請求之前執行,而Tests
中的指令碼則是在請求完成之後執行。所以,我們可以在 Pre-request Script
功能區中用指令碼先個上面兩個變數進行賦值,如:
//設定全域性變數
postman.setGlobalVariable("username", "wuhui2224");
postman.setGlobalVariable("password", "123456");
但是用 Pre-request Script
進行賦值操作仍然不能解決我們的問題,因為按照這種寫法,不論執行多少次其實都還是用固定(寫死)的資料進行測試。當然既然是指令碼語言,也會有更靈活的用法,這邊先不將。
測試資料集
接下來我們講講 Data File
, 在執行集合前的這個選項就是用來上傳測試資料(檔案)以賦值給相應變數的。我們先以 CSV
格式的測試資料為例:
username,password
wuhui2224,123456
zhangsheng,222222
yangqianjian,123456
chendaole,444444
資料格式類似表格,第一行表示對應的變數名,下面 4 行表示 4 組賬號密碼資料(其中兩組為正確資料) ,我們儲存一份內容為上述示例資料字尾名為.csv
的檔案後,再次開始測試看看效果:
我們選擇執行次數為 4 (對應 4 組測試資料)、選擇對應的 CSV
檔案執行後,可以看到我們的結果確實如我們的預期。介面 Request
執行的結果為兩次成功兩次失敗,也就是每一次執行都賦值了不同的賬號密碼的測試資料 (在最新的桌面客戶端版本中可以看到每次具體的請求情況,這邊就不再細說了)。
如果使用 Json
檔案的話,那麼格式如下:
[
{
"username": "wuhui2224",
"password": "123456"
},
{
"username": "zhangsheng",
"password": "222222"
},
{
"username": "yangqianjian",
"password": "123456"
},
{
"username": "chendaole",
"password": "444444"
}
]
定期任務
Postman
提供了一個 Monitors
(監視器)功能,支援我們提交一個測試任務,安裝設定的定時器進行執行,如每小時測試一次,具體操作如下:
請求依賴問題
講完介面結果判斷和集合批量測試後,我們再來看看比較複雜的情況,即依賴請求問題,比如我們的購物下訂單介面要求必須先登入後才可訪問。但大部分依賴問題其實本質上就是一個介面間資料傳遞的問題,比如呼叫登入介面後返回一個標識,假設為 token
,那麼我們請求下訂單介面時只要一起攜帶 token
引數進行請求即可。所以,問題變為:
- 保證介面呼叫順序
- 將介面A返回的資料傳遞給後續的介面B、C、D
介面執行順序
首先,說明一下,接下來說的介面都是預設屬於同一個集合 (Collections)
中的。
還是以我們上文中建立好介面集合為例,如果你有注意我們執行批量測試的結果,就會發現介面的執行順序其實就是按照這邊目錄中的順序(從上到下),即: Request1 -> Request2 -> Request3
。
這邊介面名字可能有點誤導性,所以再強調一下: 按目錄中從上到下的順序執行 (與字典排序無關)
所以有了這個預設的執行順序後,那麼我們便可以把需要優先執行的介面放前面即可,比如把“登入介面”放在第一個。
自定義執行順序
當然,如果只有預設的一個執行順序的話,通常沒法滿足我們複雜的業務需求,所以 Postman
為我們提供了一個函式:postman.setNextRequest("填寫你要跳轉的介面名")
,支援我們跳轉到指定介面繼續執行,舉個例子:
我們在執行完 Request1
介面成功後,不需要再執行 Request2
而是直接跳至 Request3
,那麼我可以在 Request1
介面的 Tests
功能區中執行跳轉程式碼,如:
這裡需要注意幾點:
postman.setNextRequest()
只在執行集合測試的時候生效,也就是說我們單獨執行(Send)
介面Request1
時,函式是不起作用的。- 當我們執行集合測試成功從
Request1 -> Request3
後,如果Request3
後面還有介面,那麼後面的介面仍然繼續按預設順序執行,即圖中的介面Request4
仍會被執行。 - 指定的跳轉介面必須屬於同一個集合中。
setNextRequest()
函式不管在Tests
指令碼中何處被呼叫,它都只在當前指令碼最後才被真正執行。比如我們將圖中的第二行與第一行互調後,那麼在執行跳轉函式後第二行程式碼仍會被執行。
所以,利用 setNextRequest()
函式,我們便可以按照條件跳過不必要的介面,或者建立我們自己的一個邏輯測試。
資料傳遞
在講資料傳遞前,先聊聊 Postman
中全域性變數、環境切換的使用。
全域性變數
全域性變數的概念其實我們在上文中講 Pre-request Script
時有簡單提到,也就是說我們可以通過指令碼程式碼來設定全域性變數,我們可以看看執行上文的指令碼後的效果:
我們可以看到執行後,username
和 password
兩個變數已經被成功儲存下來,那麼我們在任意介面中便都可以通過變數引用的語法如:{{username}}
來使用它們。
另外,Postman
不僅支援程式碼設定全域性變數的方式,它還支援視覺化操作:
進入對應介面後,便可直接進行管理:
多環境區分與切換
通常情況下,我們的介面都會分為測試版本和線上版本(或者更多),而他們的區別可能僅是 ULR
不同,那麼全域性變數便不大合適解決這個問題。
引數的建立
可能你已經注意到,上圖中我已經建有幾個不同環境的引數“集合”了,再看一下:
我在每個環境中都建立了一個 host
引數,如:
當然,我們的環境引數也可以通過指令碼的方式來進行設定,函式為:
//注意,該引數只新增到你當前選擇的環境的“引數集”中
postman.setEnvironmentVariable("variable_key", "variable_value");
使用與切換
環境“引數集” 中的引數使用方式和全域性變數一致,如圖中 {{host}}
,不同環境的切換見下圖:
解決依賴問題
掌握以上的預備知識後,我們開始看看如何用 Postman
解決存在依賴關係的介面測試。
假設場景
我們的介面 Request1
為登入介面,登入成功將會返回一個 access_token
欄位作為標識(已實現)。那麼假設介面 Request3
為一個下訂單的介面,需要攜帶登入返回的 access_token
才能正常訪問。
思路
- 保證
Request1
在Request3
之前被執行 - 將
Request1
返回的access_token
的值新增到環境變數”引數集”中。 Request3
在請求時引用access_token
的值
將返回值存在 “全域性變數” 或者 “環境變數” 中,視具體業務情況而定,該例中
access_token
的值是與環境有關的,所以這裡選擇使用環境變數集儲存。
Postman 中的操作
我們目錄中已保證
Request1
介面優先執行Request1
中Tests
的程式碼情況:if(responseCode.code === 200 && responseBody.has("access_token")){ //如果 code 為 200, 並且返回的資料中存在 access_token 關鍵字,則認為登入成功 tests["login"] = true; //將返回的內容轉為 json 格式,並且取到 access_token 內容,新增到環境變數中 var jsonData = JSON.parse(responseBody); //access_token的取值方式視具體的 json 資料結構而定 postman.setEnvironmentVariable("token",jsonData.result.access_token); //跳轉到 Request3 介面 postman.setNextRequest("Request3") }else{ tests["login"] = false; //登入失敗,可以選擇跳轉到對應失敗後的處理介面進行測試 //postman.setNextRequest("Other Request") }
在介面
Request3
中使用變數token
:我這邊是將
token
放在頭部資訊中, 具體使用方式時介面引數規則而定。
執行並檢視結果
執行集合測試,可以看到我們結果符合我們的預期,Request1
和 Request3
通過測試,Request2
被跳過,Request4
仍被執行。
Done……