Grafana K6 是一款專為效能測試而設計的開源工具。它非常適合大規模測試 API、微服務和網站,讓開發人員和測試人員深入了解系統效能。本備忘單將涵蓋每位性能工程師開始使用 Grafana K6 時應了解的關鍵面向。
Grafana K6 是一款面向開發人員和測試人員的現代負載測試工具,它使效能測試變得簡單、可擴展,並且易於整合到 CI 管道中。
透過 Homebrew 或 Docker 安裝 Grafana K6:
brew install k6 # Or with Docker docker run -i grafana/k6 run - <script.js
以下是如何使用公用 REST API 來執行簡單測試。
import http from "k6/http"; import { check, sleep } from "k6"; // Define the API endpoint and expected response export default function () { const res = http.get("https://jsonplaceholder.typicode.com/posts/1"); // Define the expected response const expectedResponse = { userId: 1, id: 1, title: "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", body: "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto", }; // Assert the response is as expected check(res, { "status is 200": (r) => r.status === 200, "response is correct": (r) => JSON.stringify(JSON.parse(r.body)) === JSON.stringify(expectedResponse), }); sleep(1); }
要執行測試並在 Web 儀表板中查看結果,我們可以使用以下命令:
K6_WEB_DASHBOARD=true K6_WEB_DASHBOARD_EXPORT=html-report.html k6 run ./src/rest/jsonplaceholder-api-rest.js
這將在報告資料夾中產生一個名為 html-report.html 的報告。
但我們也可以透過造訪以下 URL 在 Web 儀表板中查看結果:
http://127.0.0.1:5665/
存取 URL 後,我們可以在 Web 儀表板中即時查看測試結果。
使用公用 GraphQL API 的範例。
如果您不知道什麼是 GraphQL API,可以存取以下網址:什麼是 GraphQL? 。
有關我們將要使用的 GraphQL API 的更多信息,您可以訪問以下 URL 的文檔:GraphQL Pokémon。
有關如何測試 GraphQL API 的更多信息,您可以訪問以下網址:GraphQL 測試。
這是一個簡單的測試,用於透過名稱獲取寶可夢並檢查回應是否成功。
import http from "k6/http"; import { check } from "k6"; // Define the query and variables const query = ` query getPokemon($name: String!) { pokemon(name: $name) { id name types } }`; const variables = { name: "pikachu", }; // Define the test function export default function () { const url = "https://graphql-pokemon2.vercel.app/"; const payload = JSON.stringify({ query: query, variables: variables, }); // Define the headers const headers = { "Content-Type": "application/json", }; // Make the request const res = http.post(url, payload, { headers: headers }); // Define the expected response const expectedResponse = { data: { pokemon: { id: "UG9rZW1vbjowMjU=", name: "Pikachu", types: ["Electric"], }, }, }; // Assert the response is as expected check(res, { "status is 200": (r) => r.status === 200, "response is correct": (r) => JSON.stringify(JSON.parse(r.body)) === JSON.stringify(expectedResponse), }); }
在一個地方定義全域設定選項,例如效能閾值、虛擬使用者 (VU) 數量和持續時間,以便於修改。
brew install k6 # Or with Docker docker run -i grafana/k6 run - <script.js
將程式碼分離成可重複使用的模組,例如,將常數和請求與測試邏輯分開。
對於我們的 REST API 範例,我們可以建立一個 Constants.js 檔案來儲存 API 的基本 URL,並建立一個 requests-jsonplaceholder.js 檔案來儲存與 API 互動的函數。
import http from "k6/http"; import { check, sleep } from "k6"; // Define the API endpoint and expected response export default function () { const res = http.get("https://jsonplaceholder.typicode.com/posts/1"); // Define the expected response const expectedResponse = { userId: 1, id: 1, title: "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", body: "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto", }; // Assert the response is as expected check(res, { "status is 200": (r) => r.status === 200, "response is correct": (r) => JSON.stringify(JSON.parse(r.body)) === JSON.stringify(expectedResponse), }); sleep(1); }
現在我們可以建立 requests-jsonplaceholder.js 檔案來儲存與 API 互動的函數。
K6_WEB_DASHBOARD=true K6_WEB_DASHBOARD_EXPORT=html-report.html k6 run ./src/rest/jsonplaceholder-api-rest.js
最後,我們可以建立測試腳本 jsonplaceholder-api-rest.js 來使用我們在 requests-jsonplaceholder.js 檔案中建立的函數。
http://127.0.0.1:5665/
我們的腳本程式碼現在更容易理解,並且如果 URL、參數發生變化或需要添加新方法,則需要進行更改的位置會集中起來,從而使我們的解決方案更易於擴展隨著時間的推移。
我們可以透過創建更多的原子函數來進一步改進我們的腳本,如果有必要,我們可以重複使用這些原子函數來創建更複雜的場景,這樣就更容易理解我們的測試腳本的作用。例如,如果我們想測試貼文是否存在,我們可以建立一個取得貼文並回傳回應的函數,然後我們可以在測試腳本 jsonplaceholder-api-rest.js 中使用此函數。
import http from "k6/http"; import { check } from "k6"; // Define the query and variables const query = ` query getPokemon($name: String!) { pokemon(name: $name) { id name types } }`; const variables = { name: "pikachu", }; // Define the test function export default function () { const url = "https://graphql-pokemon2.vercel.app/"; const payload = JSON.stringify({ query: query, variables: variables, }); // Define the headers const headers = { "Content-Type": "application/json", }; // Make the request const res = http.post(url, payload, { headers: headers }); // Define the expected response const expectedResponse = { data: { pokemon: { id: "UG9rZW1vbjowMjU=", name: "Pikachu", types: ["Electric"], }, }, }; // Assert the response is as expected check(res, { "status is 200": (r) => r.status === 200, "response is correct": (r) => JSON.stringify(JSON.parse(r.body)) === JSON.stringify(expectedResponse), }); }
我們可以修改constants.js檔案以新增GraphQL API的基本URL和我們需要使用的標頭。
// ./src/config/options.js export const options = { stages: [ { duration: '1m', target: 100 }, // ramp up to 100 VUs { duration: '5m', target: 100 }, // stay at 100 VUs for 5 mins { duration: '1m', target: 0 }, // ramp down ], thresholds: { http_req_duration: ['p(95)<500'], // 95% of requests should complete in under 500ms }, };
現在我們可以建立 requests-graphql-pokemon.js 檔案來儲存與 GraphQL API 互動的函式。
// ./src/utils/constants.js export const BASE_URLS = { REST_API: 'https://jsonplaceholder.typicode.com', };
此時我們可以建立測試腳本來使用我們在 requests-graphql-pokemon.js 檔案中建立的函數。我們將創建一個簡單的測試腳本,用於獲取口袋妖怪的數據並檢查響應是否成功。
// ./src/utils/requests-jsonplaceholder.js import { BASE_URLS } from './constants.js'; import http from 'k6/http'; export function getPosts() { return http.get(`${BASE_URLS.REST_API}/posts`); } export function getPost(id) { return http.get(`${BASE_URLS.REST_API}/posts/${id}`); } export function createPost(post) { return http.post(`${BASE_URLS.REST_API}/posts`, post); } export function updatePost(id, post) { return http.put(`${BASE_URLS.REST_API}/posts/${id}`, post); } export function deletePost(id) { return http.del(`${BASE_URLS.REST_API}/posts/${id}`); }
與api rest 的範例相同,我們可以透過創建更多原子函數來改進我們的腳本,如果需要的話,我們可以重複使用這些原子函數來創建更複雜的場景,這樣就更容易理解我們的測試腳本的內容是的。
還有更好的方法來優化並對回應和請求結果進行更好的參數化,您認為我們可以做什麼?
使用動態資料來模擬更真實的場景並載入不同的資料集。 K6 允許我們使用共享數組從檔案載入資料。共享數組是一種儲存資料的方式,所有 VU 都可以存取。
我們可以建立一個 users-config.js 檔案來從 JSON 檔案 users.json 載入使用者資料。
brew install k6 # Or with Docker docker run -i grafana/k6 run - <script.js
import http from "k6/http"; import { check, sleep } from "k6"; // Define the API endpoint and expected response export default function () { const res = http.get("https://jsonplaceholder.typicode.com/posts/1"); // Define the expected response const expectedResponse = { userId: 1, id: 1, title: "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", body: "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto", }; // Assert the response is as expected check(res, { "status is 200": (r) => r.status === 200, "response is correct": (r) => JSON.stringify(JSON.parse(r.body)) === JSON.stringify(expectedResponse), }); sleep(1); }
然後我們可以在測試腳本 jsonplaceholder-api-rest.js 中使用它。
K6_WEB_DASHBOARD=true K6_WEB_DASHBOARD_EXPORT=html-report.html k6 run ./src/rest/jsonplaceholder-api-rest.js
組織良好的專案結構有助於維護和擴展您的測試。以下是建議的資料夾結構:
http://127.0.0.1:5665/
這種結構有助於保持專案組織有序、可擴展且易於維護,避免專案根目錄混亂。
另一種選擇是按功能將測試腳本分組到資料夾中,您可以測試和比較對您的上下文最有意義的內容。例如,如果您的專案是關於進行交易的錢包,您可以為每種類型的交易(存款、提款、轉帳等)建立一個資料夾,並且在每個資料夾內您可以擁有該特定交易的測試腳本。
import http from "k6/http"; import { check } from "k6"; // Define the query and variables const query = ` query getPokemon($name: String!) { pokemon(name: $name) { id name types } }`; const variables = { name: "pikachu", }; // Define the test function export default function () { const url = "https://graphql-pokemon2.vercel.app/"; const payload = JSON.stringify({ query: query, variables: variables, }); // Define the headers const headers = { "Content-Type": "application/json", }; // Make the request const res = http.post(url, payload, { headers: headers }); // Define the expected response const expectedResponse = { data: { pokemon: { id: "UG9rZW1vbjowMjU=", name: "Pikachu", types: ["Electric"], }, }, }; // Assert the response is as expected check(res, { "status is 200": (r) => r.status === 200, "response is correct": (r) => JSON.stringify(JSON.parse(r.body)) === JSON.stringify(expectedResponse), }); }
在第二個範例中,我們有一個更複雜的資料結構,但我們仍然可以重複使用為第一個範例建立的相同請求函數。
K6 效能測試對於識別瓶頸和確保應用程式可擴展性至關重要。透過遵循模組化程式碼、集中配置和使用動態資料等最佳實踐,工程師可以建立可維護和可擴展的效能測試腳本。
大大的擁抱。
查理自動化
以上是Grafana Kheat 表:性能工程師應該知道的一切的詳細內容。更多資訊請關注PHP中文網其他相關文章!