一、今天的目標:測那顆你按過的按鈕
Day 3 逛 QuickPizza 時,你按過「Pizza, Please!」,網站回給你一份披薩推薦。畫面背後發生的事:瀏覽器對一個 API 端點送出你的條件(例如熱量上限、是否素食),伺服器算出推薦後回傳。今天的任務就是測這個 API——而且整支腳本由 Claude Code 生成,你負責兩件更重要的事:把需求說清楚,以及驗收產出。
先講結論等一下會用到的背景資訊。這個 API 的資訊在 k6 官方文件的範例中都有公開:端點是 POST https://quickpizza.grafana.com/api/pizza,呼叫時要帶一個示範用的 token(abcdef0123456789)。這個 token 是官方文件印出來給全世界練習用的公開資訊——請注意這是唯一的例外情境,真實世界的 token 是機密,永遠不該出現在文章或腳本裡(Day 2 注意事項講過的原則)。
二、需求描述的五個要素
先看一個反面示範。如果你對 Claude Code 說「幫我寫一個壓測腳本」,它會生出一支能跑的腳本——但測哪裡、幾個人、怎樣算成功,全部是它自己假設的。腳本能跑,你卻無從驗收,因為連「對不對」的標準都不存在。

圖 1:模糊需求與清楚需求的分岔——需求的品質,決定你之後驗證得動的程度
清楚的需求包含五個要素,這也是之後整個系列描述任何測試的固定格式:

圖 2:需求五要素——對象、人數、時長、驗證、間隔
• 對象:測哪個網址或 API 端點,用什麼方法(GET/POST)、要帶什麼資料
• 人數:幾個虛擬使用者(VU)——記得練習站的規矩,小流量
• 時長:跑多久
• 驗證:怎樣算成功——至少包含狀態碼,能的話再加回應內容的檢查
• 間隔:動作之間停多久——沒有間隔的腳本是機器人攻擊(Day 1 講過)
給 QA 的類比:這五要素其實就是測試案例的「前置條件、步驟、預期結果」換了個形狀。你寫測項的專業,在這裡直接變成下 prompt 的專業——會描述測試的人,就會描述需求給 AI。
三、動手做:生成你的第一支腳本
進入 perf-testing 資料夾、啟動 claude,把五要素組成一段 prompt 送出:
Prompt 1|五要素齊備的生成需求
我是不會寫程式的測試人員。請幫我建立一個 k6 測試腳本,
存成 pizza-api-test.js,需求如下:
1. 對象:POST https://quickpizza.grafana.com/api/pizza,
內容是 JSON,例如 {"maxCaloriesPerSlice": 500, "mustBeVegetarian": false},
要帶 header「Authorization: Token abcdef0123456789」
(這是練習站官方公開的示範 token)
2. 人數:5 個虛擬使用者
3. 時長:30 秒
4. 驗證:狀態碼是 200,而且回應內容不是空的
5. 間隔:每次請求之間停 1 秒
腳本裡請加上繁體中文註解,解釋每一段在做什麼。
它會請求建立檔案的權限——複習 Day 3 的習慣:看一眼它要建的檔名與內容再允許。生成的腳本大致如下(AI 每次的寫法會略有差異,重點是內容涵蓋你的五要素):
import http from 'k6/http';
import { check, sleep } from 'k6';
// ── 測試設定:人數與時長(要素 2、3)─────────
export const options = {
vus: 5, // 5 個虛擬使用者
duration: '30s', // 跑 30 秒
};
// 練習站官方公開的示範 token(僅限練習站使用)
const HEADERS = {
'Content-Type': 'application/json',
'Authorization': 'Token abcdef0123456789',
};
export default function () {
// ── 要素 1:對象──「Pizza, Please!」背後的 API
const payload = JSON.stringify({
maxCaloriesPerSlice: 500, // 每片熱量上限
mustBeVegetarian: false, // 是否限定素食
});
const res = http.post(
'https://quickpizza.grafana.com/api/pizza',
payload,
{ headers: HEADERS }
);
// ── 要素 4:驗證──怎樣算成功
check(res, {
'狀態碼是 200': (r) => r.status === 200,
'回應內容不是空的': (r) => r.body && r.body.length > 0,
});
sleep(1); // ── 要素 5:間隔──停 1 秒
}
接著請它執行(或自己在另一個終端機跑 k6 run pizza-api-test.js)。輸出裡先看兩個地方:checks 是否 100%,以及 http_req_duration 的數字——POST 要經過伺服器運算,通常會比 Day 1 測首頁的 GET 慢一些,這是正常的。
四、生成之後,必問的三個問題
腳本能跑只是起點。每次讓 AI 生成任何腳本,接下來這三問是固定動作,各自守住一個目的:
必問一|這段在做什麼(守住理解)
請逐段解釋 pizza-api-test.js,用白話文,
特別是 JSON.stringify 和 headers 那兩段在做什麼。
必問二|為什麼這樣寫(守住合理性)
為什麼 payload 要放在函式裡面、HEADERS 放在函式外面?
這樣寫和全部放在函式裡有什麼差別?
必問三|我改哪裡會影響什麼(守住掌控權)
如果我想做以下調整,各要改哪一行?
1. 人數改成 10 個
2. 熱量上限改成 300
3. 驗證多加一條「回應時間低於 800 毫秒」
請列出對照表,先不要動手改。
第三問的「先不要動手改」是刻意的:讓它列出修改對照表而非直接改,你就得到一份這支腳本的「可調整參數地圖」——下次要改就自己動手,改完再請它檢查。掌控權要一點一點拿回來,這正是從「會用 AI」到「會帶 AI」的差別。
五、驗收 AI 的產出:讀、跑、看

圖 3:三層驗證——讀(對照需求)、跑(小流量試跑)、看(輸出如預期)
三層驗證是每支 AI 生成腳本的驗收流程。第一層「讀」:拿著你的五要素逐條對照腳本,五條都找得到對應段落才算過。第二層「跑」:正式測之前先用 1 個 VU 試跑一輪確認會動。第三層「看」:輸出的 checks 與數字是否如預期。
實驗:故意讓驗證失敗一次
第三層最需要練習,所以我們故意弄壞它一次。把腳本裡的這一行:
'狀態碼是 200': (r) => r.status === 200,
改成預期 201(自己動手改,不用麻煩 AI):
'狀態碼是 201': (r) => r.status === 201,
再跑一次,輸出會出現這樣的畫面(節錄):
✗ 狀態碼是 201
↳ 0% — ✓ 0 / ✗ 145
✓ 回應內容不是空的
checks_succeeded...: 50.00% 145 out of 290
系統壞了嗎?沒有——伺服器一直好好地回 200,是驗證條件寫錯了。這個分辨能力極其重要:之後每次看到 checks 失敗,第一個問題永遠是「系統真的有問題,還是驗證條件不對」。測試工具只會忠實回報比對結果,判斷失敗的意義是人的工作。驗證完把 200 改回去,並重跑確認恢復 100%。
六、注意事項:讓 AI 生成腳本時

給 RD 的一句話:最後一條「驗證條件本身也要被驗證」,就是測試圈說的「測試你的測試」。QA 同事今天用故意改壞 check 的方式練這件事——你在寫單元測試時讓測試先紅再綠的習慣,是同一個道理,兩邊可以用這個共同語言對話。
七、觀念驗證:三個問題確認你有帶走今天的重點
• 同事對 AI 說「幫我壓測一下會員 API」就直接拿產出的腳本去跑——用五要素檢查,他的需求缺了哪些?風險是什麼?(第二節)
• AI 生成的腳本跑出 checks 60%,你的第一個判斷動作是什麼?為什麼不是直接回報「系統有問題」?(第五節)
• 為什麼必問三要加「先不要動手改」?這句話在保護什麼?(第四節)
八、小結
今天你完成了第一支由自己定義、AI 生成、自己驗收的測試腳本。帶走三樣東西:需求五要素(對象、人數、時長、驗證、間隔)、生成後必問三問(在做什麼、為什麼、改哪裡)、驗收三層(讀、跑、看)。還有那個故意弄壞的實驗留下的判斷力:checks 失敗時,先問是系統壞了還是驗證錯了。這一套流程,之後每一支腳本都會重複使用。
附錄:本篇 prompt 與指令速查
# 執行今天生成的腳本
k6 run pizza-api-test.js
# 驗收試跑(第二層:小流量)
k6 run --vus 1 --duration 10s pizza-api-test.js
需求五要素範本(之後每次生成腳本都可套用):
五要素 prompt 範本
我是不會寫程式的測試人員。請幫我建立一個 k6 測試腳本,
存成 ______.js,需求如下:
1. 對象:(方法+網址+要帶的資料或 header)
2. 人數:___ 個虛擬使用者
3. 時長:___
4. 驗證:(至少狀態碼;能的話加回應內容檢查)
5. 間隔:每次請求之間停 ___ 秒
腳本裡請加上繁體中文註解,解釋每一段在做什麼。