測試開發之介面篇-使用K6完成介面自動化測試

陳琦發表於2023-04-21

K6是一個優秀的開源效能測試工具,它提供了簡潔又豐富的API,靈活和易用的描述性語法。以下列出K6中的幾個概念:

  • Metrics:測試度量的指標。如請求響應時間、執行耗時、檢查點透過率、失敗次數等;
  • Thresholds:定義了指標度量的成功、失敗標準。如請求失敗率小於5%,迭代執行耗時平均小於3秒;
  • Checks:測試用例的檢查點。如響應狀態碼等於200,響應內容包括文字關鍵字等;
  • Tags:可作用於請求、指標、閥值和檢查點的標籤,便於分類進行統計;
  • Groups:以函式的形式對指令碼進行邏輯劃分,以方便進行分類統計分析;
  • Scenarios:用於控制效能測試中的加壓方式和過程,如虛擬使用者數量和載入、併發集合點、迭代模式等。

本文針對介面測試的目標,需要我們在指令碼中實現以下的控制處理,這裡不涉及更多的效能測試的有關內容。

  1. 控制併發使用者數和介面呼叫次數;
  2. 驗證指定編號用例的請求響應時間平均值小於6秒;
  3. 驗證某個分組中請求的響應時間90%小於6秒;
  4. 驗證某個分組整體指令碼執行時間平均值小於6秒;
  5. 使用多級分組模擬測試套件及其子套件;
  6. 支援在檢查點配置測試用例編號和名稱;
  7. 輸出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測試結果、並提交到禪道測試管理系統中。

專題目錄

相關文章