· testing / vitest / playwright

Test pyramid đã chết — chiến lược kiểm thử thay thế năm 2026

Tỷ lệ 70/20/10 không có nguồn chính thức. Vitest v4.1.7 và Playwright v1.60.0 xóa ranh giới tầng test. Chiến lược kiểm thử cụ thể cho từng loại dự án 2026.

Bởi

2.061 từ · 11 phút đọc

Test pyramid chưa bị thay thế. Nó đã bị đọc sai trong mười lăm năm, và bây giờ các công cụ mới làm cho sai lầm đó hiện rõ.

Lời khuyên vẫn còn đúng: kiểm thử ở nhiều mức độ khác nhau, và có ít test cấp cao hơn so với test cấp thấp. Còn lại — tỷ lệ, các tầng, hình dạng — là kinh nghiệm chung tích lũy quanh một phép ẩn dụ. Tỷ lệ “70/20/10” (70% unit, 20% integration, 10% E2E) thường được gán cho Google thực ra không xuất hiện trong bất kỳ nguồn chính thức nào của Google Testing Blog. Kiểm tra kỹ lưỡng không tìm ra bằng chứng nào. Bạn đang tối ưu cho một con số mà chưa ai có uy tín thực sự đề ra.

Năm 2026, câu hỏi cấp bách hơn là: Vitest v4.1.7 chạy “unit test” trên Chromium thật. Playwright v1.60.0 chạy component test trên trình duyệt thật, dùng cùng MSW handlers với integration test của bạn. Ranh giới giữa unit và integration không còn là triết lý nữa — nó chỉ là một config flag.

Dành cho ai

Frontend và full-stack developer đang viết test và đã tiếp thu test pyramid như một mục tiêu tỷ lệ. Nếu bạn đã tự nhiên kiểm thử ở nhiều tầng mà không lo về tỷ lệ phần trăm, hãy bỏ qua phần đầu và đọc thẳng phần công cụ.

Test pyramid đến từ đâu

Mike Cohn giới thiệu test pyramid vào khoảng năm 2009 như một hình dạng, không phải công thức. Test ở đáy (unit) thì nhanh và rẻ. Test ở đỉnh (UI/E2E) thì chậm và tốn kém. Hãy có nhiều test nhanh hơn.

Bài làm rõ của Martin Fowler năm 2018 — vẫn là nguồn chính xác nhất về chủ đề này — tóm gọn trong hai câu: “Viết test ở nhiều mức độ khác nhau. Cấp độ càng cao thì số test càng ít.” Không có tỷ lệ. Không có phần trăm. Test pyramid luôn là một heuristic trực quan về số lượng tương đối, không phải mục tiêu định lượng.

Con số 70/20/10 lan vào cộng đồng như “khuyến nghị của Google” vào khoảng thời gian Google Testing Blog đăng “Just Say No to More End-to-End Tests” (2015). Bài đó có thật và lập luận cốt lõi rất vững: “Nếu bạn chủ yếu dùng E2E test, thời gian chạy test (và số lượng test bị flaky) sẽ tăng đáng kể.” Nhưng tỷ lệ cụ thể đó không có trong bài đó, không có trong sách của Cohn, và không có trong bài làm rõ của Fowler. Nó được gán cho Google suốt một thập kỷ mà không có nguồn nào chứng minh được.

Tại sao các tỷ lệ không còn phù hợp

Dù 70/20/10 có từng là một quy định thực sự, các tiền đề khiến nó hợp lý đều đã thay đổi.

E2E flakiness vẫn là điểm nghẽn

Lập luận của Google năm 2015 vẫn còn giá trị năm 2026. Dữ liệu thực tế cho thấy E2E flakiness ở mức 15–21% trong các bộ test thực tế. Một nghiên cứu công nghiệp có peer-review phát hiện flaky test ngốn khoảng 2.5% tổng thời gian làm việc của developer — debug, chạy lại, và vòng phản hồi chậm khiến người ta không muốn chạy test ở local. E2E test chạm vào trình duyệt thật, mạng thật, và backend thật sẽ tích lũy từng mode lỗi một cách độc lập. Bạn không muốn phần lớn test của mình ở đây.

Đó vẫn là bài học thực sự của test pyramid, và nó vẫn đúng.

Ranh giới tầng giờ chỉ là một config flag

Lập luận thực tế cho “chủ yếu là unit test” là môi trường: unit test chạy trong Node.js hoặc jsdom, integration test có thể khởi động một database, E2E test cần trình duyệt. Tốc độ tỷ lệ nghịch với độ trung thực của môi trường.

Vitest v4.1.7 (phát hành ngày 20/05/2026) đưa browser mode thành tính năng ổn định. Bạn viết test trông y hệt một Vitest unit test và nó chạy trên Chromium, Firefox, hay WebKit thông qua Playwright hoặc WebdriverIO provider. Lý do chính thức rất thẳng thắn: jsdom và happy-dom “chỉ mô phỏng môi trường trình duyệt chứ không phải trình duyệt thật, điều này có thể dẫn đến sự khác biệt… Do đó, kết quả test có thể có false positive hoặc false negative.” Browser mode loại bỏ nhóm tín hiệu sai này. Nếu bạn đang cân nhắc chuyển từ Jest, Vitest vs Jest 2026 có số liệu benchmark cụ thể để quyết định.

Playwright v1.60.0 (phát hành ngày 11/05/2026) chạy component test — React, Vue, Svelte — trên trình duyệt thật với mounting API trông giống setup unit test. Các package component testing vẫn còn prefix experimental-, nên hãy xem đây là production-capable nhưng chưa chính thức ổn định. Cụ thể hơn: component test runner của Playwright nhận MSW request handlers qua router.use(handlers). Nếu bạn đang dùng MSW để mock network request trong Vitest, bạn có thể tái sử dụng các handler đó trong Playwright component test mà không cần sửa gì.

Sự phân biệt tầng unit/integration/E2E trước đây tương ứng với sự phân biệt môi trường. Giờ thì ngày càng là câu hỏi về phạm vi — test này kiểm tra bao nhiêu phần của hệ thống? — hơn là nó chạy ở đâu.

Các hình dạng thay thế nói gì

Nhiều framework đã đề xuất các lựa chọn thay thế cho pyramid. Không cái nào đạt được vị thế chuẩn tương đương, và việc kiểm chứng từ nguồn gốc không đồng đều. Đây là những gì đủ vững để áp dụng:

Testing Trophy của Kent C. Dodds đặt “integration” ở dải rộng nhất. Logic nền tảng — rằng test kiểm tra ranh giới module thực tế mang lại độ tin cậy cao hơn trên mỗi test so với pure unit test — nhất quán với cách tooling hiện đại hoạt động. Nên đọc trực tiếp bài gốcthảo luận cập nhật năm 2025 của Dodds; các khẳng định cụ thể về tỷ lệ cần kiểm chứng độc lập.

Testing Honeycomb của Spotify (2018) định hướng lại việc kiểm thử xung quanh microservices — điểm tích hợp tự nhiên giữa các service là ranh giới test tốt hơn so với việc mock các module nội bộ. Nếu bạn làm việc trong kiến trúc service-mesh, bài engineering của Spotify năm 2018 đáng đọc. Khẳng định cụ thể rằng nó “đảo ngược pyramid” nhận được sự ủng hộ không nhất quán khi kiểm chứng từ nguồn gốc; sắc thái đó có thể quan trọng với bạn.

SMURF của Google (tháng 10/2024, Testing Blog) phân loại test theo thuộc tính hành vi thay vì nhãn tầng. Từ viết tắt SMURF — Small, Medium, Useful, Reliable, Fast theo các nguồn thứ cấp — có thể dùng thuật ngữ khác trong chính bài đó. Hãy đọc trực tiếp trước khi trích dẫn; bài đó có thật và cách đặt vấn đề trông có chiều sâu, nhưng khẳng định cụ thể về SMURF không vượt qua được kiểm chứng phản biện trong quá trình nghiên cứu bài viết này. Hướng đi cơ bản (phân loại theo hành vi, không theo tên tầng) tương thích với xu hướng chung của ngành dù sao.

Điểm chung của cả ba: họ cho rằng nhãn tầng của pyramid kém hữu ích hơn so với sự rõ ràng về mức độ tin cậy bạn nhận được từ mỗi test. Dải “integration” trong Testing Trophy và tầng “medium” trong framework của Google đang làm công việc khái niệm tương tự — kiểm tra các dependency thực tế mà không cần full network stack.

Chiến lược cụ thể theo loại dự án

Bằng chứng đã được kiểm chứng ủng hộ quan điểm chung này: đừng tối ưu cho tỷ lệ; hãy tối ưu cho tỷ lệ độ tin cậy/flakiness của từng loại test trong môi trường cụ thể của bạn.

Monolith với server-rendered template

Test pyramid áp dụng rõ ràng nhất ở đây. Unit test business logic. Integration test database write và service call với database thật (Docker container trong CI là đủ). E2E test ba đến năm user journey quan trọng — đăng nhập, checkout, đăng ký. Đừng phình tầng E2E chỉ vì cảm giác nó toàn diện.

API service (REST hay GraphQL)

Bỏ qua unit test của pure function không có external dependency — độ phủ không đáng với chi phí bảo trì. Integration test endpoint của bạn với database thật. Contract test API boundary với consumer nếu bạn có. Gần như bạn không cần browser automation.

SPA nặng về frontend

Đây là nơi Vitest browser mode và Playwright component testing thay đổi phép tính. Lập luận truyền thống cho pure unit test là jsdom thì nhanh và “đủ tốt.” Nó không đủ tốt cho logic phụ thuộc layout, CSS interaction, hay bất cứ thứ gì chạm vào ResizeObserver hay IntersectionObserver. Chạy component test trong trình duyệt thật qua Vitest browser mode hoặc Playwright CT. Dùng MSW cho network boundary — các handler đó hoạt động trong cả hai. Giữ Playwright E2E cho end-to-end user journey; giữ số lượng nhỏ. Nếu bạn đang chọn E2E framework, Playwright vs Cypress 2026 so sánh hiệu suất thực tế.

// vitest.config.ts — browser mode
import { defineConfig } from 'vitest/config'

export default defineConfig({
  test: {
    browser: {
      enabled: true,
      provider: 'playwright',
      name: 'chromium',
    },
  },
})
// playwright.config.ts — component testing
import { defineConfig } from '@playwright/experimental-ct-react'

export default defineConfig({
  use: {
    ctPort: 3100,
  },
})

Việc tái sử dụng MSW handler trong cả Vitest và Playwright trông như này:

// handlers.ts — write once, use in both
import { http, HttpResponse } from 'msw'

export const handlers = [
  http.get('/api/user', () =>
    HttpResponse.json({ id: 1, name: 'Test User' })
  ),
]
// vitest: setup.ts
import { setupServer } from 'msw/node'
import { handlers } from './handlers'
const server = setupServer(...handlers)
beforeAll(() => server.listen())
afterEach(() => server.resetHandlers())
afterAll(() => server.close())
// playwright component test
import { handlers } from './handlers'

test('loads user profile', async ({ mount, page, router }) => {
  await router.use(...handlers)
  const component = await mount(<UserProfile />)
  await expect(component.getByText('Test User')).toBeVisible()
})

Kết luận

Hình dạng của pyramid vẫn còn giá trị. Phép ẩn dụ vẫn hữu ích. Các tỷ lệ số bao giờ cũng chỉ là hư cấu.

Hướng dẫn thực tế cho năm 2026:

  • Nếu bạn test pure logic không có DOM hay network: Vitest ở Node mode. Nhanh, rẻ, vẫn có giá trị.
  • Nếu bạn test UI component: Vitest browser mode (v4.1.7) hoặc Playwright component testing (v1.60.0, prefix experimental). Chạy trong trình duyệt thật. Vấn đề false signal của jsdom được giải quyết bằng cách chuyển môi trường, không phải bằng cách viết thêm E2E test.
  • Nếu bạn test user journey: Playwright E2E. Giữ số lượng nhỏ. Flakiness tích lũy theo độ phủ; mười journey ổn định hơn năm mươi cái mong manh.
  • Nếu bạn test API surface: Integration test với dependency thật trong CI. Không cần trình duyệt.

Tầng bạn nên giảm thiểu — trong bất kỳ hình dạng nào, pyramid hay trophy hay honeycomb — là tầng có tỷ lệ flakiness cao nhất trên mỗi đơn vị độ tin cậy. Trong hầu hết dự án, đó vẫn là E2E. Test pyramid đã đúng điều đó. Các con số cụ thể xung quanh nó luôn là nhiễu.

Tài liệu tham khảo

  1. Martin Fowler — The Practical Test Pyramid (2018)
  2. Google Testing Blog — Just Say No to More End-to-End Tests (2015)
  3. Google Testing Blog — SMURF: Beyond the Test Pyramid (2024)
  4. Vitest Browser Mode documentation
  5. Why Vitest Browser Mode? (official rationale)
  6. Vitest releases — v4.1.7
  7. Playwright release notes — v1.60.0
  8. Playwright Component Testing — network requests with MSW
  9. Kent C. Dodds — The Testing Trophy and Testing Classifications
  10. Kent C. Dodds — Does the Testing Trophy need updating for 2025?
  11. Spotify Engineering — Testing of Microservices (Honeycomb, 2018)
  12. Leinen et al. — Cost of Flaky Tests in CI: An Industrial Case Study (ICST 2024)
  13. Atlassian Engineering — Taming Test Flakiness