在上一篇 《接口測試利器Postman - 基礎篇》中,我們介紹了 Postman 工具的主要功能和一些基本用法。 其實 Postman 作為目前使用最為廣泛的接口測試工具,除了能提供互動良好的 UI 界面以及完成基本的http協定的鑒權、header、body 等的設定以及請求送出和響應解析這些基本功能外,它還提供了非常豐富的測試輔助能力。本篇我們就來為大家詳細介紹 postman 的腳本進階功能。
Postman的變量
在接口測試工具中,變量對于接口消息的重用和靈活比對意義重大,作為一個專業的接口測試工具,對變量的支援是必須具備的。
而 Postman 就提供了豐富的變量支援,在 Postman 中定義了5種不同作用範圍的變量類型,在變量的使用和管理上更加地靈活和有針對性。下圖是官方給出的不同類型變量的作用範圍
從外向内作用域逐漸變小,同時生效優先級越高,也就是當存在同一變量名時,内層變量類型的變量會優先生效。下面我們結合執行個體來具體說明一下這些變量類型的作用範圍:
global 變量
global 變量即全局變量,是作用範圍最大的一種變量類型。設定好 global 變量後,可以在 Postman 工具中所有可以使用變量的地方生效。
下面在 Postman 工具中看一下 global 變量的設定: 在工具右上角打開環境管理界面:
選擇 global 變量管理:
添加 Global 變量:
此例中,我們設定一個 global 變量 name,取值為 1。 在 Postman 中,使用雙花括号表示變量,形如 {{ variable }}。以 Github API 為例,比如我們擷取使用者名為變量 name 取值的使用者資訊。
https://api.github.com/users/{{name}}
url中輸入雙花括号後會自動聯想出我們需要的變量類型。
發送請求後,檢查 Postman 響應區,可以看到我們擷取了 username 為 1 的使用者資訊。
{
"login": "1",
"id": 1825798,
"node_id": "MDQ6VXNlcjE4MjU3OTg=",
"avatar_url": "https://avatars2.githubusercontent.com/u/1825798?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/1",
"html_url": "https://github.com/1",
"followers_url": "https://api.github.com/users/1/followers",
"following_url": "https://api.github.com/users/1/following{/other_user}",
"gists_url": "https://api.github.com/users/1/gists{/gist_id}",
"starred_url": "https://api.github.com/users/1/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/1/subscriptions",
"organizations_url": "https://api.github.com/users/1/orgs",
"repos_url": "https://api.github.com/users/1/repos",
"events_url": "https://api.github.com/users/1/events{/privacy}",
"received_events_url": "https://api.github.com/users/1/received_events",
"type": "User",
"site_admin": false,
"name": "Michael",
"company": null,
"blog": "",
"location": "San Francisco, CA",
"email": "[email protected]",
"hireable": null,
"bio": null,
"public_repos": 3,
"public_gists": 0,
"followers": 15,
"following": 0,
"created_at": "2012-06-07T06:10:07Z",
"updated_at": "2019-01-17T08:29:21Z"
}
Collection 與 Collection 變量
再來看另一個變量類型 Collection 變量。首先了解下 Collection 的概念。Collection 是 Postman 中組織接口的一個集合機關,Postman 中也主要以 Collection 為配置存儲的一個基本機關。我們可以把 Collection 看作軟體測試中測試用例集的概念。
Collection 變量就是作用域在 Collection 上的變量類型,這種變量隻會在設定變量的 Collection 上生效。 設定方法:選擇 Edit Collection
在 variable 頁中添加 Collection 變量,本例中我們在 Github 這個 Collection 添加一個同樣命名為name 的變量
将上例中擷取使用者的接口儲存到 Github 這個 Collection 中(我們可以在 Collection 下再建立一層子目錄,注意目錄是不支援設定目錄級别的變量的,Collection 變量在子目錄下的接口依然會生效),我們再送出一下這個接口
此時可以看到,我們設定的 Collection 變量已經生效,擷取到的是 name 為 2 的使用者資訊。注意此時我們還設定了一個 name 為 1 的 global 變量,可以看到 Collection 變量的優先級高于 global變量。
環境和 environment 變量
環境是 Postman 中的一個非常有用的概念。做過軟體測試的同學都了解,我們在實際工作中會接觸到不同的軟體環境。對應于我們被測試系統的不同運作場景。比如一般網際網路企業在研發中會存在以下的一些不同環境:
- 開發環境
- 內建環境(聯調環境)
- 系統測試環境
- 試生産環境
- 生産環境
- 性能測試環境
- 安全測試環境
不同的環境在接入途徑、網絡拓撲、通路權限以及硬體配置上往往都有較大差別。Postman 中引入 Environment 這個概念,通過 Environment 變量來管理一組環境配置,便于我們來友善地在不同環境間進行切換。
在環境管理界面中,可以添加環境,以及該環境對應的相關變量。本例我們添加一個 GitChat 環境,并且設定一個 name = 3 的環境變量。
設定完環境後,我們再剛才的擷取使用者接口界面上,選擇對應的 GitChat 環境,再重新送出請求。可以看到環境變量已經生效,擷取了name為 3 的使用者資訊,同樣可以看到,此時環境變量的優先級比 Collection 又要更高。
data 變量
另一種 Postman 中的變量類型是 data 變量,data 變量隻能在 Postman Runner 中使用,也就是會在 Runner 運作時才生效,data 變量可以提供多組測試資料供接口測試時調用,為 Postman 提供接口批量資料驗證能力。要使用 data 變量,打開 Postman Runner, 如下圖,選擇 data 變量定義檔案加載 data 變量檔案。
data 變量支援json或者txt/csv資料格式,json 定義格式如下,
[
{
"id":"11",
"name":"user1"
},
{
"id":"12",
"name":"user2"
},
{
"id":"13",
"name":"user3"
}
]
txt/csv 格式如下:
id,name
11,user1
12,user2
13,user3
在 runner 界面上可以通過 preview 檢視運作時不同疊代所加載的變量取值,如下:
如本例,點選 Run variables 會執行 3 次不同的疊代,通過 Postman Console檢視運作日志,可以看到每次均使用了 data 變量中定義的對應變量值。 同樣,雖然我們選擇 environment,但可以看到 data 變量在 runner 運作時優先級更高。
local 變量
Local 變量在 Postman 官方文檔中并沒有給出明确的定義。一般可以了解成 Postman 腳本中支援的 JS 變量,它的作用域隻會在腳本中生效, 此時 Postman 界面引用的 {{variable}} 并不會取到 local 變量值。 腳本中直接引用的變量名會取local變量,其他資料類型則通過 Postman 對應的取值語句來擷取。
比如我們在 Pre-Request 中定義以下腳本并執行:
在 Console 中檢視結果如下,可以比較清楚地看到每次執行在預執行腳本中不同變量的目前取值
通過以上執行個體,我們可以看到,Postman 針對不同的接口作用範圍支援了豐富的變量類型,使我們在應用變量功能的時候可以更加的靈活
Postman 腳本及其執行順序
除了支援豐富的變量功能,Postman 還支援強大的腳本功能,測試人員在進行接口測試時,可以通過腳本來動态地對接口測試邏輯進行定制,再結合變量,就可以實作一些複雜的場景。
Postman 的腳本功能是基于 Node.js 語言,Node.js 成熟的文法和豐富的擴充庫給 Postman 提供了巨大的靈活性和強力的擴充能力。
在 Postman 中,測試腳本 可以在接口發送之前和收到響應之後執行,分别對應 Pre-request Script 和 Test Script,如下圖:
比如我們前文介紹變量時的執行個體,其實就是一個 pre-request 腳本
除了接口本身可以設定 pre-request 和 Test Script,我們在編輯 Collection 和 Collection 下的folder時,可以看到 Collection 和 Folder 也都支援設定 pre-request 和 test 腳本。 那這幾種腳本的執行優先級或者說順序是如何的呢? 下圖就是這幾個不同位置腳本的調用執行順序:
對TestNG 或者 Junit 等測試架構有所了解的同學,應該知道這些測試架構也有類似的運作時概念,也就是 Setup 和 teardown 方法,而且也有 case、class、suite 這樣的層次。不過這些不同層次的方法都是成對出現的,即 case 的 setup 和 teardown 在 case 執行前和結束後會執行。 而 Postman 的 Script 執行順序和這個稍有差别,是按層級順序排列,而不是成對出現的。大家參照圖檔注意了解下差異。
大家也可以自己驗證下這個執行順序,分别在Collection、folder 以及 folder 下的請求中定義相關腳本,如:
執行,檢視 console 輸出:
可見 Postman 對不同腳本的執行順序和前文所述一緻。
Postman腳本-PreRequest
Pre-request 腳本,顧名思義,其實就是在接口消息發送前,可以進行一些預處理動作,類似于 Junit 或 TestNG 等測試架構中的 Setup 方法。 利用 Pre-Script 腳本,我們就可以在發送接口請求前來完成一些需要動态處理的動作,比如調整變量取值,或者對一些動态參數進行一些特殊處理。
下面我們就以 GitHub API 中的一個執行個體來看下 Pre-Script 腳本的主要作用。(關于GitHub API 的一些具體說明,大家可以先看下我在上一篇 Chat 《玩轉Postman:基礎篇》中的介紹)
GitHub API 中一個經常使用到的接口是查詢接口
根據 GitHub API 官網的定義說明,查詢 repositories 的接口定義如下:
GET /search/repositories
其中參數 q 是主要的查詢參數,具體定義參見 https://help.github.com/articles/searching-for-repositories/
比如我們要查詢包含在指定日期 2018-11-11 後建立且包含關鍵字 automation 的 repository 資訊。
可知 GitHub 上存在這樣的 repo 數量有七千多個。
在這個例子中,因為查詢條件包含一個日期參數,而實際測試工作場景中,很多時候我們希望日期是動态生成的,比如根據目前日期取一年以前作為查詢參數值,這時我們就需要對參數進行一些預處理,這就是 Pre-Script 的用武之地了。
這時我們可以首先設定一個環境變量 created,再在 pre-script 腳本中動态預處理這個日期,來完成日期動态設定的目的。
pm.environment.set("created",getCreated(new Date(), -1) );
/*
擷取"YYYY-MM-DD"格式的日期
第一個入參為日期對象
第二個入參為年份偏移量,負數為向前偏移
*/
function getCreated(date, yearOffset) {
var seperator1 = "-";
var year = date.getFullYear() + yearOffset;
var month = date.getMonth() + 1;
var day = date.getDate();
if (month >= 1 && month <= 9) {
month = "0" + month;
}
if (day >= 0 && day <= 9) {
day = "0" + day;
}
var currentDate = year + seperator1 + month + seperator1 + day;
console.log(currentDate)
return currentDate;
}
在 Postman中執行如圖,擷取目前日期一年以來建立的 repositories 資訊。
在 Pre-Script中,主要是圍繞 Postman 的變量來進行預處理,是以主要使用的就是 Postman 的變量域的一些封裝方法。
- pm.globals.has(variableName:String)
是否存在某全局變量
- pm.globals.get(variableName:String)
擷取全局變量
- pm.globals.set(variableName:String, variableValue:String)
設定全局變量
- pm.globals.unset(variableName:String)
取消目前全局變量設定
- pm.globals.clear()
清空全局變量
- pm.environment.has(variableName:String)
是否存在某環境變量
- pm.environment.get(variableName:String)
擷取環境變量
- pm.environment.set(variableName:String, variableValue:String)
設定環境變量
- pm.environment.unset(variableName:String)
取消目前環境變量設定
- pm.environment.clear()
清空環境變量
- pm.variables.get(variableName:String)
根據變量名擷取變量
- pm.sendRequest()
發送請求
Postman腳本-Test腳本
Postman 的 Test 腳本是 Postman 另一個值得稱道的特色功能,在 Test 腳本中,Postman 封裝了很多豐富的校驗邏輯,并結合 JS 腳本本身語言的靈活性,給測試人員對接口的判斷、校驗和響應處理帶來極大的便利性。
下面我們重點介紹下 Test 腳本中封裝一些主要的校驗方法。
判斷接口響應狀态碼
對接口響應狀态碼的校驗,是接口測試校驗的常用手段。關于狀态碼的詳細說明也可參見我的上一篇 Chat 《玩轉Postman:基礎篇》 , 下面看一個 Postman 中進行接口校驗碼校驗的代碼:
pm.test("判斷傳回成功狀态碼",function(){
pm.response.to.have.status(200);
});
或者也可以使用第三方校驗庫 chaijs 的expect 方法來進行校驗。 Chaijs 對常用的校驗方式按照行為驅動開發(BDD)的描述方式進行了封裝,使校驗判斷的代碼編寫友善了很多。
pm.test("expect方法判斷傳回成功",function(){
pm.expect(pm.response.code).to.equal(200)
});
再或者我們還可以直接使用 Postman 對傳回狀态碼的封裝方法來進行判斷
pm.test("Postman封裝方法判斷傳回成功",function(){
pm.response.to.be.ok
});
Postman 中直接封裝了常見的傳回狀态校驗方法:
- pm.response.to.be.info
校驗 1XX 資訊狀态碼
- pm.response.to.be.success
校驗 2XX 成功狀态碼
- pm.response.to.be.redirection
校驗 3XX 重定向狀态碼
- pm.response.to.be.clientError
校驗 4XX 用戶端錯誤狀态碼
- pm.response.to.be.serverError
校驗 5XX 服務端錯誤狀态碼
- pm.response.to.be.error
校驗 4XX 或 5XX 錯誤狀态碼
- pm.response.to.be.ok
檢驗 200 的 OK 傳回
- pm.response.to.be.accepted
校驗狀态碼 202 的接受傳回
- pm.response.to.be.badRequest
校驗狀态碼 400 的請求消息錯誤
- pm.response.to.be.unauthorized
校驗狀态碼 401 的認證錯誤
- pm.response.to.be.forbidden
校驗狀态碼 403 的通路受限
- pm.response.to.be.notFound
校驗狀态碼 404 的資源未見錯誤
- pm.response.to.be.rateLimited
校驗狀态碼 429 的通路頻次限制錯誤
校驗響應時間
除了對于傳回碼的校驗,我們還會經常校驗的一個響應名額是響應時間。Postman 對于響應時間的校驗也非常簡單
pm.test("響應時間小于1s", function () {
pm.expect(pm.response.responseTime).to.be.below(1000);
});
校驗消息内容
對接口傳回内容的校驗是我們判斷業務邏輯正确性與否的必要手段。響應的消息頭或者消息體内容我們可以通過 pm.response.header 或者 pm.response.text 、 pm.response.json 來擷取。在相應的校驗代碼中我們就可以根據擷取到的内容來進一步判斷響應的正确性
pm.test("校驗消息頭Content-Type", function () {
pm.expect(postman.getResponseHeader("Content-Type")).to.include("application/json")
});
pm.test("校驗消息體傳回數量大于1000", function () {
var jsonData = pm.response.json();
pm.expect(jsonData.total_count).to.gt(1000)
});
在 Postman 中執行以上校驗,可以在 Response 的 Test Results 中看到校驗結果
Postman腳本-接口的關聯
在接口測試中,經常出現的一種情況是:我們需要從另一個接口的響應中擷取某些值作為目前測試接口的輸入來使用。結合 Postman 的 Pre-Script 腳本和 Test 腳本以及變量功能,我們可以友善地完成内容擷取和參數傳遞的場景。
以下面的場景為例:
從 Junit5 這個 repo 的接口資訊中,擷取該 repo 的建立時間,再查詢在這個時間之後建立的所有包含 Junit5 字樣的 repo 資訊,判斷 repo 數量是否超過 1000
方法一:
- 設定一個環境變量 created
- 在擷取 repo 接口 GetRepo 的 Test 腳本中擷取 Junit5 這個 repo 的建立時間
- 在 Test 腳本中将擷取到的建立時間指派給環境變量 created
- 在查詢 repo 接口中使用環境變量 created
- 在查詢 repo 接口中添加判斷傳回數量的校驗代碼
- 通過 Runner 執行器按順序執行這兩個接口,完成關聯執行
如圖:
在 Runner 執行器中執行結果
方法二:
在方法一中我們利用環境變量來傳遞參數,這種方法需要依賴 runner 執行器對接口的執行順序來保證 GetRepo 接口在 SearchRepo 接口之前執行。
我們也可以利用 Postman 提供的請求發送方法 pm.sendRequest 在 SearchRepo 的 pre-Script 腳本中直接完成前置請求的發送和參數擷取。
pm.sendRequest('https://api.github.com/repos/junit-team/junit5', function (err, res) {
if (err) {
console.log(err);
} else {
pm.environment.set("created", res.json().created_at);
}
});
此時不需要利用 runner 執行器,直接執行 SearchRepo 接口,也可得到同樣的結果
Postman腳本-代碼複用
Postman 作為一個接口測試工具而不是專業的代碼編輯 IDE, 并沒有提供腳本的複用以及代碼片、子產品定義之類的功能。但借助 Postman 強大的變量和 js 文法的良好支援,我們可以變通地實作代碼複用。
我們可以将一些常用的代碼片段儲存到 global 變量中, 在需要使用的時候,直接調用這個 global 變量即可。
比如上面判斷傳回 repo 數量是否超過 1000 這段校驗代碼:
pm.test("判斷傳回成功狀态碼",function(){
pm.response.to.have.status(200);
});
pm.test("校驗消息體傳回數量大于1000", function () {
var jsonData = pm.response.json();
pm.expect(jsonData.total_count).to.gt(1000)
});
我們将它設定在 global 變量 checkRepoCount 中,在需要調用的地方,以如下代碼代替即可:
eval(globals.checkRepoCount)
Postman 中如圖:
Postman腳本-一個結合第三方庫的複雜場景案例
Postman 為便于接口腳本的編寫,内建支援了豐富的第三方庫,官方文檔中列出了詳細清單
除了前面提到的 BDD 校驗庫 chai, 下面我們再結合第三方時間處理庫 moment 來完成一個相對複雜的場景案例實作:
1. 擷取最近 6 個月包含有 Junit5 字樣且 Star 數 >1 的 repo 資訊
2. 判斷傳回 repo 數量是否 >0, 結果顯示到 Test Result
3. 如果數量 >0 , 擷取 star 數最多的 repo 資訊
4. 判斷自己是否已經 star 過這個repo
5. 如果沒有 star 過,執行 star操作
相關的接口如下:
- 查詢接口,查詢關鍵字 junit5,star 數 >1 , 建立時間 6 月内, 按 star 數降序查詢
/search/repositories?q=junit5+stars:>1+created:>{{created}}&sort=stars
- 查詢是否 star 了某 repo
GET /user/starred/:owner/:repo
已 star 傳回 204,未 star 傳回 404
- 執行 star repo 操作
PUT /user/starred/:owner/:repo
成功則傳回 204
在查詢repo接口的 Pre-Script 腳本中引入事件處理庫 moment,可以看到 moment 庫相比 js 本身的 date 方法,對日期的處理更加方法靈活,利用 subtract 方法可簡單擷取半年前的日期,無需考慮日期補零、跨年等判斷,代碼如下:
var m = require("moment")
//利用 moment 庫擷取六個月前日期
let createDate = m(m.now()).subtract(6,"months").format("YYYY-MM-DD")
pm.environment.set("created", createDate);
在查詢repo接口的 Test 腳本中編寫校驗和後續邏輯代碼:
//擷取符合條件repo總數量
let count = pm.response.json().total_count
pm.test("覆寫條件repo數量為 "+count, function(){
if( count > 0 ){
//儲存repo的owner和repo名稱,查詢條件為按star排序,是以index為0的repo即star數最多
var repoName = pm.response.json().items[0].name
var owner = pm.response.json().items[0].owner.login
pm.test("目前star數最多的repo是【"+ pm.response.json().items[0].full_name + "】", function(){
//需要定義請求資訊,指定header和執行方法。不指定的話直接在SendRequest中使用預設為GET方法,不攜帶Header
const getStarReq = {
url: "https://api.github.com/user/starred/"+owner+"/"+repoName,
method: 'GET',
//接口需要經過鑒權,代碼中不能使用Postman界面設定,将鑒權資訊攜帶在header中
header:'Authorization:Bearer 84fb9e0706bab75f1d4b6f4e3586683d8c4605af'
}
pm.sendRequest(getStarReq, function (err, res) {
if (err) {
console.log(err);
} else {
let stared = pm.test("目前repo已star",function(){
if (res.code === 404){
const starRequest = {
url: "https://api.github.com/user/starred/"+owner+"/"+repoName,
method: 'PUT',
//接口需要經過鑒權,代碼中不能使用Postman界面設定,将鑒權資訊攜帶在header中
header: 'Authorization:Bearer 84fb9e0706bab75f1d4b6f4e3586683d8c4605af'
}
pm.sendRequest(starRequest, function (starErr, starRes){
if (starErr) {
console.log(starErr);
} else {
pm.test("已star成功",function(){
pm.expect(starRes.code).to.equal(204)
})
}
})
}
pm.expect(res.code).to.equal(204)
})
}
})
})
}
})
Postman 中執行效果如圖:
結語
以上就是關于 Postman 的腳本進階使用的介紹。簡單總結一下:
- Postman 提供了 5 種不同的變量類型,且分别對應不同的作用域。靈活使用這些變量,可以幫助我們實作動态比對、參數傳遞、代碼複用等場景。
- postman 在 Collection、Folder、接口本身三層上都分别提供了兩種腳本沙箱:Pre-Script、Test。Pre-Script是在接口請求之前執行,Test 是在接口響應之後執行。注意三層對象上不同的執行順序。
- Postman 腳本基于 Node.js,内建支援了豐富的第三方庫,并且 Postman 自身也封裝了很多上層方法,可以參考 Postman 官方沙箱方法參考
是以Postman 通過豐富的變量以及強大的 js 腳本支援,可以非常靈活地幫助我們更好地完成接口測試中一些複雜的場景。