K6是一個優秀的開源效能測試工具,它提供了簡潔又豐富的API,靈活和易用的描述性語法。以下列出K6中的幾個概念:
- Metrics:測試度量的指標。如請求響應時間、執行耗時、檢查點透過率、失敗次數等;
- Thresholds:定義了指標度量的成功、失敗標準。如請求失敗率小於5%,迭代執行耗時平均小於3秒;
- Checks:測試用例的檢查點。如響應狀態碼等於200,響應內容包括文字關鍵字等;
- Tags:可作用於請求、指標、閥值和檢查點的標籤,便於分類進行統計;
- Groups:以函式的形式對指令碼進行邏輯劃分,以方便進行分類統計分析;
- Scenarios:用於控制效能測試中的加壓方式和過程,如虛擬使用者數量和載入、併發集合點、迭代模式等。
本文針對介面測試的目標,需要我們在指令碼中實現以下的控制處理,這裡不涉及更多的效能測試的有關內容。
- 控制併發使用者數和介面呼叫次數;
- 驗證指定編號用例的請求響應時間平均值小於6秒;
- 驗證某個分組中請求的響應時間90%小於6秒;
- 驗證某個分組整體指令碼執行時間平均值小於6秒;
- 使用多級分組模擬測試套件及其子套件;
- 支援在檢查點配置測試用例編號和名稱;
- 輸出JSON格式的測試結果摘要和日誌檔案。
下面我們看一下示例的指令碼,完整的指令碼檔案請訪問GitHub。
import http from 'k6/http';
import exec from 'k6/execution';
import { check, sleep, group } from "k6";
export const options = {
// 設定併發使用者數及其載入方式
stages: [
{ duration: "2s", target: 3 }, // 2秒內,載入3個虛擬使用者
{ duration: "1s", target: 0 }, // 1秒內,銷燬所有虛擬使用者
],
// 設定效能有關指標的閥值,形如{id:1}標籤的指標會影響指定用例的成敗。
thresholds: {
// 驗證編號為1的用例的響應時間,平均值小於1000毫秒
'http_req_duration{id:1}': ['avg < 1'],
// '使用者登入'分組中所有請求的響應時間,90%小於6000毫秒
'http_req_duration{group:::登入請求}': ['p(90) < 6000'],
// '使用者登入'分組的整體執行時間,平均值小於6000毫秒
'group_duration{group:::登入請求}': ['avg < 6000'],
},
};
export default function () {
// 單元測試套件
group('使用者登入', function () {
let resp = http.get('https://httpbin.org/get?p1=1', {
tags: { id: '1' }, // 標記用例編號為1,用於上述閥值統計
});
// 期待響應狀態碼
let expectRespStatus = 200
// 透過設定錯誤的期待結果,模擬三分之一的迭代失敗
// if (+`${exec.vu.idInTest}` % 3 === 0) {
// expectRespStatus = 222
// }
// console.log(`in iteration ${exec.vu.idInTest}, expectRespStatus=${expectRespStatus}`)
// 驗證器方法,可以驗證響應的狀態碼、耗時、內容等
const validator = (r) => resp.status == expectRespStatus
// 注意:此處的檢查點和前面定義的閥值'http_req_duration{id:1}'均會影響用例的成敗
// 斷言方法(用例ID, 用例名稱,驗證點名稱,被驗證資料,驗證器)
assert(1, '微信掃碼登入', '驗證跳轉到個人儀表盤', resp, validator);
// 子套件'使用者登入-登入次數限制'及其下用例程式碼
group('失敗次數限制', function () {
assert(0, '登入失敗連續3次,賬號鎖定', '顯示賬號已被鎖定', resp, (r) => true);
assert(0, '登入非連續性失敗累計達到3次,賬號不鎖定', '可成功登入', resp, (r) => true);
assert(0, '鎖定賬號15分鐘後自動解禁', '解禁後可成功登入', resp, (r) => true);
});
// 當前套件'使用者登入'下的另一個用例
group('CASE', function () {
assert(0, '郵箱登入', '驗證到達首頁', resp, (r) => resp.status == 200);
});
sleep(1);
});
group('使用者管理', function () { // 單元測試套件
const resp = http.post('https://httpbin.org/post', JSON.stringify({
foo: 'abc',
bar: '123',
}), {
tags: { foo: 'bar' },
headers: {
'Content-Type': 'application/json',
},
});
// 驗證器
const validator = (data) => {
const status = data.status
const dur = data.timings.duration
// console.log('===', status, dur)
// 驗證狀態碼和響應時間
const pass = status == 200 && dur < 6000
return pass
}
// 斷言:用例ID, 用例名稱,驗證點名稱,被驗證資料,驗證器
assert(0, '重置密碼', '驗證使用者收到密碼重置右鍵', resp, validator);
sleep(1);
});
}
export function setup() {
console.log('--- setup')
}
export function teardown(data) {
console.log('--- teardown')
}
// 配置ZTF執行時請保留該函式,否則thresholds閥值結果不會影響用例結果
// export function handleSummary(data) {
// return {
// 'results/summary.json': JSON.stringify(data), //the default data object
// };
// }
function assert (caseId, caseName, checkpoint, data, validator) {
const name = `${caseId} - ${caseName}`
const tags = { id: caseId, name: caseName, checkpoint: checkpoint}
check(data, { [name]: validator }, tags);
}
在命令列執行以下命令:
k6 run main.js
得到下列控制檯輸出:
running (05.0s), 0/3 VUs, 3 complete and 0 interrupted iterations
default ✓ [======================================] 0/3 VUs 3s
█ setup
█ 使用者登入
✓ 1 - 微信掃碼登入
█ 失敗次數限制
✓ 0 - 登入失敗連續3次,賬號鎖定
✓ 0 - 登入非連續性失敗累計達到3次,賬號不鎖定
✓ 0 - 鎖定賬號15分鐘後自動解禁
█ CASE
✓ 0 - 郵箱登入
█ 使用者管理
✓ 0 - 重置密碼
█ teardown
checks.........................: 100.00% ✓ 18 ✗ 0
data_received..................: 20 kB 4.0 kB/s
data_sent......................: 2.2 kB 443 B/s
group_duration.................: avg=857.26ms min=25.43µs med=604.99ms max=2.02s p(90)=1.84s p(95)=1.92s
✓ { group:::登入請求 }.............: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s
http_req_blocked...............: avg=320.83ms min=0s med=307.26ms max=668.21ms p(90)=655.24ms p(95)=661.73ms
http_req_connecting............: avg=107.18ms min=0s med=101.03ms max=238.79ms p(90)=220.52ms p(95)=229.66ms
http_req_duration..............: avg=392.41ms min=205.38ms med=283.97ms max=702.8ms p(90)=686.37ms p(95)=694.58ms
{ expected_response:true }...: avg=392.41ms min=205.38ms med=283.97ms max=702.8ms p(90)=686.37ms p(95)=694.58ms
✓ { group:::登入請求 }.............: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s
✓ { id:1 }.....................: avg=257.77ms min=205.38ms med=209.42ms max=358.51ms p(90)=328.69ms p(95)=343.6ms
http_req_failed................: 0.00% ✓ 0 ✗ 6
http_req_receiving.............: avg=92.33µs min=60µs med=98µs max=125µs p(90)=115.49µs p(95)=120.25µs
http_req_sending...............: avg=348.5µs min=206µs med=306µs max=565µs p(90)=499µs p(95)=531.99µs
http_req_tls_handshaking.......: avg=211.06ms min=0s med=206.07ms max=429.09ms p(90)=427.12ms p(95)=428.1ms
http_req_waiting...............: avg=391.97ms min=204.69ms med=283.6ms max=702.28ms p(90)=685.91ms p(95)=694.09ms
http_reqs......................: 6 1.19129/s
iteration_duration.............: avg=2.05s min=51.71µs med=3.03s max=3.69s p(90)=3.64s p(95)=3.66s
iterations.....................: 3 0.595645/s
vus............................: 1 min=1 max=3
vus_max........................: 3 min=3 max=3
指令碼執行結束後,K6會以他預設的形式來展示測試日誌和結果。為了達成上述的介面測試目標,下文我們將介紹,如何分析K6測試結果、並提交到禪道測試管理系統中。