E2E 測試天生就愛壞,壓力測試讓你睡得好
一句話總結:E2E 測試只測最值錢的流程,壓力測試告訴你系統在哪個點會斷裂。
結論先講:如果你用 E2E 測試覆蓋所有情境,你會花 80% 的時間在修 flaky test 而不是寫功能。壓力測試則是你上線前最不想省的一步。
E2E 測試:模擬真人操作
E2E 測試做的事情很直觀——開一個真的瀏覽器(或 headless browser),模擬使用者點擊、輸入、跳轉,看整個流程走不走得通。
聽起來很美好?問題是 E2E 測試有幾個天生的痛點:
- 慢:一個測試跑幾秒到幾十秒是常態
- 脆弱:DOM 結構一改、動畫時間一變、網路稍微慢一點,測試就壞了
- 定位模糊:測試失敗時,你不知道是前端壞了、後端壞了、還是資料庫壞了
所以 E2E 測試的策略是:只測最關鍵的流程,不要貪多。
什麼叫「最關鍵的流程」?就是那些壞掉的話會直接影響營收或使用者信任的路徑:
- 註冊 → 登入 → 核心操作(下單、付款、發文…)
- 關鍵的 Happy Path
- 跨系統的端到端驗證
其他的邊界條件、異常路徑?交給 Unit Test 和 Integration Test 去處理。
E2E 測試的存活指南
寫 E2E 測試最怕的就是 flaky——同一份測試有時過有時不過,沒改任何 code。幾個減少 flaky 的做法:
- 不要用
sleep(3000)這種硬等,用waitForSelector或cy.intercept等動態等待 - 測試資料要獨立——每個測試用自己的資料集,不要共享
- 執行環境要穩定——專用的測試環境,不要跟開發環境搶資源
- 如果你非得用 retry,那是止血,不是治療。記得回頭找根因
工具怎麼選?
- Cypress:開發體驗最好,自動等待機制、時間旅行除錯都很強。但只支援 Chromium 系瀏覽器是個限制
- Playwright:跨瀏覽器支援(Chrome、Firefox、Safari),自動程式碼生成,微軟出品。需要跨瀏覽器測試的話選它
- Selenium:最老牌,支援最多語言。但開發體驗相對差,通常是 legacy 系統或有特殊需求才用
我的建議?新專案直接選 Playwright 或 Cypress。如果團隊已經在用 Selenium 而且跑得好好的,不用為了潮而換。
壓力測試:找出系統的天花板
壓力測試回答的問題很實際:我們的系統能撐多少人同時用?瓶頸在哪?
如果你跳過壓力測試就上線,那你就是拿你的使用者當白老鼠。運氣好沒事,運氣不好上線第一天系統崩潰,公司公關危機、使用者流失、老闆的眼神——你不會想體驗的。
四種測試類型
不是所有壓力測試都一樣,看你想驗證什麼:
- Load Test:模擬正常流量,確認系統穩定。「我們預期的日常負載扛不扛得住?」
- Stress Test:逐步加壓直到系統崩潰。「系統的極限在哪?瓶頸是 CPU、記憶體還是資料庫?」
- Spike Test:瞬間灌入大量請求。「搶票、閃購那種場景撐得住嗎?」
- Soak Test:中等負載長時間跑。「跑 24 小時會不會 memory leak?」
關鍵指標
壓力測試看什麼數字?
- 回應時間:P50(中位數)、P95、P99 的延遲分佈。P99 才是真正會咬你的那個數字
- 吞吐量(QPS / RPS):每秒處理多少請求
- 錯誤率:非 2xx 回應的比例。超過 5% 就要認真看了
- 資源使用率:CPU、Memory、Disk I/O、Network
實戰範例:k6 壓力測試
k6 是我最推薦的壓力測試工具——用 JavaScript 寫腳本、輕量、CI 友善。來看一個實際的腳本:
import http from 'k6/http';
import { check, sleep, group } from 'k6';
import { Rate, Trend } from 'k6/metrics';
const errorRate = new Rate('errors');
const orderTrend = new Trend('order_creation_duration');
export const options = {
stages: [
{ duration: '1m', target: 50 }, // 慢慢爬到 50 人
{ duration: '3m', target: 50 }, // 維持 50 人觀察穩定性
{ duration: '1m', target: 100 }, // 加壓到 100 人
{ duration: '3m', target: 100 }, // 維持觀察
{ duration: '2m', target: 0 }, // 緩慢降回
],
thresholds: {
http_req_duration: ['p(95)<500', 'p(99)<1000'],
errors: ['rate<0.05'],
order_creation_duration: ['p(95)<800'],
},
};
export default function (data) {
const headers = {
'Content-Type': 'application/json',
'Authorization': `Bearer ${data.token}`,
};
group('瀏覽商品', () => {
const res = http.get(`${BASE_URL}/api/v1/products?page=1`, { headers });
check(res, { '回傳 200': (r) => r.status === 200 });
errorRate.add(res.status !== 200);
sleep(1);
});
group('建立訂單', () => {
const payload = JSON.stringify({
items: [{ productId: 'prod-001', quantity: 1 }],
});
const res = http.post(`${BASE_URL}/api/v1/orders`, payload, { headers });
check(res, { '建立成功': (r) => r.status === 201 });
errorRate.add(res.status !== 201);
orderTrend.add(res.timings.duration);
sleep(2);
});
}注意 thresholds 的設定——這是你跟系統之間的合約:P95 回應時間必須低於 500ms,錯誤率必須低於 5%。k6 跑完會直接告訴你有沒有違約。
其他壓力測試工具
- Artillery:YAML 配置,Node.js 生態系,支援 WebSocket
- JMeter:GUI 操作,功能最豐富,但學習曲線陡
- Locust:Python 寫腳本,分散式支援好,Python 團隊首選
這篇的重點回顧
E2E 測試只測最值錢的流程,用動態等待取代硬等,工具選 Playwright 或 Cypress。壓力測試用 k6 定義效能合約,四種測試類型對應四種不同的問題。
下一篇是這個系列的最終章——怎麼把這些測試整合進 CI/CD pipeline,以及測試過程中最常見的坑。
系列文章:
- 測試策略(一):測試金字塔
- 測試策略(二):Unit Test 與 Integration Test
- 你在這裡 → 測試策略(三):E2E 測試與壓力測試
- CD 整合與常見陷阱
延伸閱讀:
「壓力測試就像體檢——你不做它不代表沒病,只是你不知道而已。」