POSTMAN 通常是目前在做 API 層級的測試時的首選,不過通常 API 的測試不會只有 End-to-End 的測試就結束了,有些較完整的還會包含負載測試(Load Test),不過若只有用 POSTMAN 就想要完成 Load test 那就辛苦了。
POSTMAN Test Script#
這邊我們就使用 POSTMAN 自帶的 Collection (Postman Echo) 來做實驗,這邊簡單起見就只抓一個 Get method 來做。匯出的檔案大概會長以下這樣:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
| {
"info": {
"_postman_id": "{_postman_id}",
"name": "{your_collection_name}",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"item": [
{
"name": "{your_request_name}",
"event": [
{
"listen": "test",
"script": {
"id": "e6b1db6b-fac1-4f5c-820e-d0a6806b1a1e",
"exec": [
"tests[\"Body contains headers\"] = responseBody.has(\"headers\");",
"tests[\"Body contains args\"] = responseBody.has(\"args\");",
"tests[\"Body contains url\"] = responseBody.has(\"url\");",
"",
"var responseJSON;",
"",
"try { responseJSON = JSON.parse(responseBody); }",
"catch (e) { }",
"",
"",
"tests[\"Args key contains argument passed as url parameter\"] = 'test' in responseJSON.args"
],
"type": "text/javascript"
}
}
],
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "https://postman-echo.com/get?test=123",
"protocol": "https",
"host": [
"postman-echo",
"com"
],
"path": [
"get"
],
"query": [
{
"key": "test",
"value": "123"
}
]
},
"description": "The HTTP `GET` request method is meant to retrieve data from a server. The data\nis identified by a unique URI (Uniform Resource Identifier). \n\nA `GET` request can pass parameters to the server using \"Query String \nParameters\". For example, in the following request,\n\n> http://example.com/hi/there?hand=wave\n\nThe parameter \"hand\" has the value \"wave\".\n\nThis endpoint echoes the HTTP headers, request parameters and the complete\nURI requested."
},
"response": []
}
],
"protocolProfileBehavior": {}
}
|
這個方式的缺點就是 Postman 匯出的最小單位是 Collection ,所以很可能實際運用時你會需要把本機測試用的 Collection 與壓力測試用的分成兩個 Collection。
What is K6#
過往做負載測試很多都會用 JMeter 來做,JMeter 教學資源很多同時可以自行開發外掛以符合需求,也可以使用 GUI 進行設定,最大的缺點大概就是整體運行偏笨重相依 JVM,而且測試腳本的分享比較不好進行版控(內容比對不容易看出來到底改了什麼),改用 POSTMAN 來進行 API 測試設定快速又好上手,畢竟使用 JMeter 來測試還是比較 heavy 一點。不過使用 POSTMAN 來測試會遇到一個問題,那就是壓力測試 POSTMAN 本身並不支援,為了讓測試的體驗可以更完整,讓壓測可以利用 POSTMAN 完成我們可以借助 K6 這套工具來達成這個效果,讓我們可以把 POSTMAN 所存的 API request 都抓來壓一壓。
Install K6#
官方教學
其實若是 Windows 使用者的話可以直接下載。若是不想處理環境等相關問題的話,K6 本身有提供 Docker 版本可以下載,雖然在執行時會需要啟動 Docker 但是可以確保執行環境的一致性也是個好處。
值得一提的是 K6 雖然是執行 javascript 但是他並不需要 NodeJS,他是用 Golang 寫的,只是附帶一個 javascript 的執行環境。
Convert to K6#
雖然 K6 可以做壓測但他本身並不直接支援 POSTMAN 所匯出的檔案,我們會需要一套轉換工具將 POSTMAN 匯出的 json 檔案轉換成 K6 可以執行的 js 檔案。要做到這個我們可以利用 NodeJS 的一個套件 postman-to-k6 來完成,它能將 POSTMAN 匯出的 json 檔案轉換成 K6 可以理解的形式,包含 PreRequest scripts / Test scripts / variables 等。但是有些行為是不支援的,需要改成 K6 的寫法,無法支援的功能請參考這裡。
讓我們條列一下步驟
Install NodeJS
ref: https://nodejs.org/en/
Install postman-to-k6 module
npm install -g postman-to-k6
Export POSTMAN collection
就是單純的把 POSTMAN 裡要做壓測的 Collection 給 export 出成 json 檔案。
Convert your POSTMAN collection to K6 script
postman-to-k6 postman_collection_export.json -o k6-script.js
轉換完畢應該至少會有兩個檔案,一個 JS 檔就是要 K6 執行的 script,另一個就是他會用到的 library 檔。
就這樣!簡單的四個步驟就完成執行壓測的前置作業了!
產出的檔案大概會類似這樣
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
| // Auto-generated by the Load Impact converter
import "./libs/shim/core.js";
export let options = { maxRedirects: 4 };
const Request = Symbol.for("request");
postman[Symbol.for("initial")]({
options
});
export default function() {
postman[Request]({
name: "GET Request Copy",
id: "7af25195-60ed-4c1b-b372-1469ea7112c7",
method: "GET",
address: "https://postman-echo.com/get?test=123",
post(response) {
tests["Body contains headers"] = responseBody.has("headers");
tests["Body contains args"] = responseBody.has("args");
tests["Body contains url"] = responseBody.has("url");
var responseJSON;
try {
responseJSON = JSON.parse(responseBody);
} catch (e) {}
tests["Args key contains argument passed as url parameter"] =
"test" in responseJSON.args;
}
});
}
|
若你跟我一樣抓 POSTMAN Echo 來實驗的話,直接把轉譯過的 script 跑 K6 那肯定會遇到問題,我們在後面一點來解題。
Setup K6 Parameters#
K6 本身提供了很多參數來作為執行時對測試的控制,而最直覺也是最重要的參數莫過於 VUs (virtual users)了,這個就是指明你要模擬多少使用者來打這個 API。不過我個人比較常用的是另外幾個設定,Stages / Thresholds。
Stages 相較於設定 VUs 讓 K6 自己決定人數的變化,使用這個可以控制更多細節,以下是個簡單的範例:
1
2
3
4
5
6
| stages: [
{ duration: "1m", target: 60},
{ duration: "1m", target: 80},
{ duration: "1m", target: 60},
{ duration: "1m", target: 0}
]
|
這邊就是全程跑 4分鐘,然後每一分鐘的 VUs 會到多少,這也是目前我個人比較常用的壓測方式。
而另一個 Thresholds 就是判定怎樣的 request 算是成功,這邊的設定與 POSTMAN 的 test script 所偏向的商業邏輯面比較不同,這邊所設定的閥值通常比較像是效能有關的,可以參考官方的說明:Thresholds。
1
2
3
| thresholds: {
http_req_duration: [{ threshold: 'p(95)<100', abortOnFail: false, delayAbortEval: '1m'}],
}
|
這個範例就是我指明 request 的全程花費時間的 P 值在信心度 95 的狀況下要有 100ms 就回應我的效能,否則算失敗,且就算失敗也不要停止。而以下就是試跑的結果:
Execute K6 and Export Result#
最簡單又直接的執行指令就是
k6 run k6-script.js
而輸出的話預設就會是在 console 畫面中印出來。也可以把一些 options 當作參數傳入,但我個人偏好把這些 options 寫在檔案裏面。
若你是照搬我這邊的範例的話需要改寫一下 POSTMAN 的 test script 才不會出錯。
首先要在 k6 script 引入
import "./libs/shim/expect.js";
這個套件,我們的測試語法會需要用到它。
而 default function 裡的 post 就改成
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| // post 這邊傳入的參數其實就是 POSTMAN 打過去的 request 以及相關的數值,涵蓋回應時間等資料
post(pmRequest) {
pm.test("Body contains headers", function(){
var jsonData = pm.response.json();
pm.expect(jsonData).to.have.property("headers");
});
pm.test("Body contains args", function(){
var jsonData = pm.response.json();
pm.expect(jsonData).to.have.property("args");
});
pm.test("Body contains url", function(){
var jsonData = pm.response.json();
pm.expect(jsonData).to.have.property("url");
});
pm.test("Args key contains argument passed as url parameter", function(){
var jsonData = pm.response.json();
pm.expect(jsonData.args).to.have.property("test")
});
}
|
Conclusion#
POSTMAN 在這短短幾年內可以說是席捲了在 API 開發與測試的一套工具,他的簡單易用以及 script 方便納入版控的特性深獲眾多開發者的心,但他目前針對壓測等較為 heavy 的測試的支援是較為不足的,還好有很多好用的工具可以跟他搭配,讓 POSTMAN 與這些測試的相容更為容易,也有越來越多的 QA/QE 在使用這套工具,可以直接把 RD 在開發時的一些 test script 稍加調整後就能併入整合測試/壓力測試中,這也讓開發團隊內部之間的技術可以直接分享。我想未來 POSTMAN 在開發與測試 API 這塊應該會持續佔有領導地位吧~
Reference#