測試金字塔
是什麼?
測試金字塔(Test Pyramid)是 Mike Cohn 在《Succeeding with Agile》中提出的模型,描述不同層級測試的理想比例和策略。
ℹ️指導原則,不是教條
測試金字塔是一個思考模型,不是精確的比例公式。重點是「底層多、頂層少」的原則,具體數字依專案調整。
核心觀念
- Unit Test(底層):測試單一函式或類別,毫秒級完成,數量最多。一個典型的中型專案可能有數百到數千個 Unit Test
- Integration Test(中層):測試元件之間的互動,如 API + Database,秒級完成。驗證的是元件「接起來」後有沒有問題,例如 SQL 查詢是否正確、HTTP 回應格式是否對
- E2E Test(頂層):模擬使用者操作完整流程(打開瀏覽器、點擊、填表單),分鐘級完成,數量最少。常用工具:Playwright(跨瀏覽器推薦)、Cypress(前端生態整合好)
- 速度與信心度的 Trade-off:底層快但只驗證單元邏輯(信心度低),頂層慢但最接近真實使用者行為(信心度高)。投資策略:底層廣撒網抓邏輯錯誤,頂層只覆蓋最關鍵的使用者路徑(Happy Path + 主要錯誤路徑)
- Testing Trophy:Kent C. Dodds 提出的變體,把中間的 Integration Test 畫得最大,主張它的投資報酬率最高。理由:Integration Test 能用中等的速度抓到最多真實世界的 Bug,因為大部分 Bug 出在元件之間的整合
常見誤區
⚠️失衡的測試策略
- 冰淇淋甜筒反模式:只寫 E2E 不寫單元測試,CI 跑一次要 30 分鐘,開發者不敢跑
- 只寫單元測試:每個函式都測了,但元件接起來就爆——因為沒有整合測試
- 追求 100% 覆蓋率:覆蓋率是指標,不是目標。100% 覆蓋率不代表 0 個 Bug
- 每層使用相同的工具:不同層級適合不同工具,不要用 E2E 工具寫單元測試
金字塔層級
Unit Test(底層)
大量、快速、便宜。測試單一單元的邏輯,毫秒級完成。佔比約 70%
Integration Test(中層)
適量、中速。測試元件間的互動與整合,秒級完成。佔比約 20%
E2E Test(頂層)
少量、慢速、昂貴。模擬完整使用者流程,分鐘級完成。佔比約 10%
程式碼範例
C#(xUnit)
// Unit Test — 快速,只測邏輯
public class PriceCalculatorTests
{
[Fact]
public void CalculateDiscount_VipCustomer_Gets20PercentOff()
{
var calculator = new PriceCalculator();
var result = calculator.CalculateDiscount(100m, CustomerType.Vip);
Assert.Equal(80m, result);
}
}
// Integration Test — 測 API + Database 的互動
public class OrderApiTests : IClassFixture<WebApplicationFactory<Program>>
{
private readonly HttpClient _client;
public OrderApiTests(WebApplicationFactory<Program> factory)
{
_client = factory.CreateClient();
}
[Fact]
public async Task CreateOrder_ValidRequest_ReturnsCreated()
{
var content = JsonContent.Create(new { ProductId = 1, Quantity = 2 });
var response = await _client.PostAsync("/api/orders", content);
Assert.Equal(HttpStatusCode.Created, response.StatusCode);
}
}
// E2E Test — 用 Playwright 模擬使用者
// (通常放在獨立的測試專案)
// [Fact]
// public async Task User_CanCompleteCheckout()
// {
// await page.GotoAsync("https://localhost:5001");
// await page.ClickAsync("[data-testid='add-to-cart']");
// await page.ClickAsync("[data-testid='checkout']");
// await Expect(page.Locator(".success-message")).ToBeVisibleAsync();
// }TypeScript(Jest)
// Unit Test — 只測純邏輯
describe("PriceCalculator", () => {
it("gives VIP 20% discount", () => {
const calculator = new PriceCalculator();
expect(calculator.calculateDiscount(100, "vip")).toBe(80);
});
});
// Integration Test — 測 API endpoint
describe("POST /api/orders", () => {
it("creates order and returns 201", async () => {
const response = await request(app)
.post("/api/orders")
.send({ productId: 1, quantity: 2 });
expect(response.status).toBe(201);
expect(response.body.id).toBeDefined();
});
});Python(pytest)
# Unit Test — 只測純邏輯
def test_calculate_discount_vip_gets_20_percent_off():
calculator = PriceCalculator()
result = calculator.calculate_discount(100, CustomerType.VIP)
assert result == 80
# Integration Test — 測 API + Database
def test_create_order_valid_request(client, db):
response = client.post("/api/orders", json={
"product_id": 1,
"quantity": 2
})
assert response.status_code == 201
assert db.query(Order).count() == 1概念圖
此圖呈現三種模型的關係:傳統金字塔強調 Unit Test 為基礎,Testing Trophy 把重心移到 Integration Test,而冰淇淋甜筒是大家都該避免的反模式。沒有哪個模型是絕對正確的——前端專案偏向 Trophy,後端 API 偏向傳統金字塔。
不同專案類型的比例建議
| 專案類型 | Unit | Integration | E2E | 說明 | |----------|------|-------------|-----|------| | 後端 API | 70% | 25% | 5% | 商業邏輯多,Unit Test 價值最高 | | 前端 SPA | 30% | 50% | 20% | 偏向 Testing Trophy,Integration Test 驗證元件互動 | | 微服務 | 50% | 40% | 10% | 服務間整合是主要風險,Integration Test 比重高 | | CLI 工具 | 80% | 15% | 5% | 以純邏輯為主,Unit Test 覆蓋最有效 |
實戰補充
💡資深開發者的經驗
- Testing Trophy 的觀點:Kent C. Dodds 認為 Integration Test 的投資報酬率最高,因為它能捕捉到真實的使用者流程,又不像 E2E 那麼慢。
- 每層的回饋速度不同:Unit Test 在開發時即時回饋(秒級),Integration Test 在 CI 回饋(分鐘級),E2E 在部署前回饋(十分鐘級)。
- 團隊規模影響比例:小團隊可能偏向 Testing Trophy(更多 Integration),大團隊需要更嚴格的 Unit Test 保護。
- Flaky Test 是殺手:E2E 層最容易出現不穩定的測試。如果 E2E 每次都隨機失敗,團隊會開始忽略測試結果。
理解測驗
🤔 測試金字塔建議哪一層的測試數量最多?
🤔 什麼是冰淇淋甜筒反模式?
🤔 Testing Trophy 和傳統測試金字塔的主要差異是什麼?
重點整理
💡一句話記住
口訣:「底廣頂尖像金字塔,快的多寫慢的少寫,倒過來就是甜筒災難」。
| 層級 | 速度 | 信心度 | 成本 | 建議比例 | |------|------|--------|------|----------| | Unit Test | 毫秒 | 低(只測單元) | 低 | ~70% | | Integration Test | 秒 | 中(測互動) | 中 | ~20% | | E2E Test | 分鐘 | 高(測全流程) | 高 | ~10% |