Đi tới nội dung

QA / Test Engineer

Tìm rủi ro trước người dùng và biến chất lượng thành thứ cả team đo được

Lộ trình đi từ tư duy kiểm thử và kỹ thuật thiết kế test case, qua API testing và automation với Playwright, tới kiểm thử phi chức năng, quality engineering và AI trong testing. Dành cho tester manual muốn chuyển sang automation/SDET, hoặc developer muốn hiểu nghề QA một cách nghiêm túc.

Bắt đầu từ chặng 01
chặng
10chặng
chủ đề
50chủ đề
tuần, học part-time
~36tuần, học part-time
  • Nền tảng
  • Cốt lõi
  • Nâng cao
  • PlaywrightPlaywright
  • TypeScriptTypeScript
  • Bruno
  • Pact
  • k6
  • axe-core
  • Appium
  • Maestro

Góc nhìn của mình

Mình là frontend developer, không phải QA chuyên nghiệp. Mấy năm làm sản phẩm, mình làm việc sát với các bạn tester, đọc bug report của họ mỗi ngày, rồi tự viết test Playwright cho những luồng quan trọng của app. Chính lúc đó mình mới thấy viết được một test chạy xanh khác xa việc biết nên test cái gì. Map này là những gì mình học được từ đồng đội QA và từ việc tự đào sâu, cộng với con đường mình sẽ đi nếu bắt đầu làm QA/SDET hôm nay.

Điều mình ước biết sớm hơn

  • Tool thay đổi mỗi vài năm, còn kỹ thuật thiết kế test như phân vùng tương đương hay giá trị biên thì dùng được cả đời, nên học nó trước khi học framework.
  • Một test flaky còn tệ hơn không có test, vì nó dạy cả team bỏ qua màu đỏ. Mình ước đã coi flaky là bug thật sớm hơn.
  • Bug report tốt là bug report mà developer tái hiện được trong một lần đọc. Bước tái hiện, kết quả mong đợi và bằng chứng quan trọng hơn mọi lời mô tả dài.
  • Automation không thay thế được exploratory testing. Script chỉ kiểm tra những gì mình đã nghĩ tới, còn người test giỏi tìm ra những gì chưa ai nghĩ tới.
Đã qua 0/10 chặng

Nền tảng01–03

  1. 01Chặng 01, 2 tuầnTư duy kiểm thử và các cấp độ testGiải thích được vì sao và ở cấp độ nào nên test một tính năng, dựa trên rủi ro chứ không theo cảm tính.
    Hồi đầu mình nghĩ test là để chứng minh code chạy đúng. Đồng đội QA dạy mình rằng mục tiêu thật là tìm ra thông tin về rủi ro, kể cả thông tin không ai muốn nghe.

    Kiến thức cần nắm

    Các cấp độ test
    Unit, integration, component, end-to-end và acceptance test khác nhau ở phạm vi, tốc độ và chi phí bảo trì. Hiểu ranh giới giữa chúng giúp bạn đặt mỗi kiểm tra ở cấp rẻ nhất mà vẫn bắt được lỗi. Phân biệt thêm verification (làm đúng spec) với validation (làm đúng thứ người dùng cần).
    Test pyramid và testing trophy
    Test pyramid của Mike Cohn khuyên nhiều unit test, ít E2E. Testing trophy của Kent C. Dodds dồn trọng tâm vào integration test vì chúng cho độ tự tin cao trên mỗi đơn vị chi phí. Cả hai là mô hình gợi ý, không phải luật: hình dạng phù hợp phụ thuộc kiến trúc và nơi lỗi thật hay xảy ra trong hệ thống của bạn.
    Risk-based testing
    Đánh giá rủi ro theo khả năng xảy ra nhân với mức độ ảnh hưởng, rồi phân bổ công sức test tương ứng. Luồng thanh toán, phân quyền và dữ liệu người dùng cần độ phủ sâu hơn trang giới thiệu. Một risk matrix đơn giản giúp bạn bảo vệ quyết định không test kỹ một phần nào đó.
    Shift-left và QA trong agile
    Shift-left nghĩa là QA tham gia từ lúc refine story: đặt câu hỏi về acceptance criteria, edge case và khả năng test được trước khi có dòng code nào. Các buổi three amigos (product, dev, QA) và acceptance criteria viết theo dạng Given/When/Then giúp lộ ra hiểu lầm sớm. QA hiện đại là người dẫn dắt chất lượng cho cả team, không phải cổng kiểm duyệt cuối sprint.
    Bảy nguyên lý kiểm thử
    Syllabus ISTQB CTFL v4.0 tóm tắt các nguyên lý như testing chỉ ra sự hiện diện của lỗi chứ không chứng minh không có lỗi, test toàn bộ là bất khả thi, và lỗi thường tập trung theo cụm. Những nguyên lý này nghe hiển nhiên nhưng giúp bạn tranh luận có cơ sở khi bị hỏi vì sao chưa test hết.

    Nên làm

    • Đọc acceptance criteria và viết ra câu hỏi về edge case trước khi bắt đầu implement hoặc test.
    • Gắn mỗi test với một rủi ro cụ thể để biết nó tồn tại vì lý do gì.
    • Chọn cấp độ test thấp nhất vẫn bắt được loại lỗi bạn lo ngại.
    • Ghi lại những gì bạn quyết định không test và lý do.

    Dễ sai

    • Đo chất lượng bằng số lượng test case thay vì rủi ro đã được giảm.
    • Coi QA là giai đoạn cuối sprint, để tester nhận build khi đã quá muộn để thay đổi thiết kế.

    Project chốt chặng: Risk map cho một tính năng thật

    Chọn một tính năng như đăng ký tài khoản hoặc giỏ hàng của một app bạn dùng hằng ngày, liệt kê ít nhất 10 rủi ro và chấm điểm khả năng xảy ra, mức ảnh hưởng. Đạt yêu cầu khi mỗi rủi ro có cấp độ test đề xuất (unit, integration, E2E, manual) kèm một câu giải thích.

    Kiểm tra nhanh

    Đã trả lời 0/4 · đúng 0

    Trả lời đúng ít nhất 3/4 câu để đánh dấu đã qua chặng này.

    1. Câu 1/4Cơ bảnMột pure function tính VAT và làm tròn cho tổng đơn hàng. Phần lớn các edge case về làm tròn nên được kiểm ở đâu?
    2. Câu 2/4Cơ bảnMột manager hỏi vì sao 2.000 test pass vẫn không chứng minh được release không có bug. Nguyên tắc kiểm thử nào trả lời câu này?
    3. Câu 3/4Cơ bảnBạn có hai ngày để test một release chạm vào luồng thanh toán, trang giới thiệu và upload avatar. Risk-based testing chia công sức thế nào?
    4. Câu 4/4Cơ bảnTrong buổi refinement, một story ghi 'Người dùng có thể áp mã giảm giá'. Hành động shift-left có giá trị nhất của QA là gì?
  2. 02Chặng 02, 3 tuầnThiết kế test case và exploratory testingThiết kế được bộ test case gọn mà phủ rủi ro tốt, chạy exploratory session có charter và viết bug report developer tái hiện được ngay.
    Đây là stage mình thấy developer hay bỏ qua nhất, kể cả mình. Lần đầu ngồi xem một bạn QA áp dụng giá trị biên lên một form, mình mới hiểu vì sao họ tìm ra bug nhanh như vậy.

    Kiến thức cần nắm

    Phân vùng tương đương và giá trị biên
    Equivalence partitioning chia input thành các nhóm mà hệ thống xử lý giống nhau, mỗi nhóm chỉ cần một đại diện. Boundary value analysis kiểm tra ngay tại và quanh ranh giới, ví dụ tuổi 17, 18, 65, 66 cho khoảng 18 đến 65. Đừng quên các phân vùng không hợp lệ như chuỗi rỗng, số âm, ký tự Unicode và giá trị quá dài.
    Decision table và pairwise
    Decision table liệt kê tổ hợp điều kiện và hành động tương ứng, cực hữu ích cho logic khuyến mãi hay phân quyền có nhiều nhánh. Khi tổ hợp bùng nổ, pairwise testing chọn tập con phủ mọi cặp giá trị, giảm mạnh số case mà vẫn bắt được phần lớn lỗi do tương tác hai tham số.
    State transition testing
    Vẽ sơ đồ trạng thái cho đối tượng có vòng đời như đơn hàng (draft, paid, shipped, cancelled) rồi test cả chuyển trạng thái hợp lệ lẫn không hợp lệ. Lỗi hay nằm ở các chuyển trạng thái bị cấm nhưng hệ thống vẫn cho phép, ví dụ huỷ đơn đã giao hoặc thanh toán hai lần.
    Exploratory testing với charter
    Exploratory testing là học, thiết kế và thực thi test đồng thời, có cấu trúc chứ không phải bấm lung tung. Một charter theo mẫu của Elisabeth Hendrickson có dạng: khám phá vùng X, với nguồn lực Y, để tìm thông tin Z. Session-based test management đóng khung mỗi phiên 60 đến 90 phút và kết thúc bằng ghi chú, bug và câu hỏi mở.
    Bug report developer muốn đọc
    Một bug report tốt có tiêu đề nêu triệu chứng và vị trí, bước tái hiện tối thiểu, kết quả thực tế so với mong đợi, môi trường (trình duyệt, build, tài khoản test) và bằng chứng như screenshot, video, HAR hoặc trace ID. Tách severity (mức ảnh hưởng kỹ thuật) khỏi priority (thứ tự xử lý theo business). Một bug, một report.

    Nên làm

    • Với mỗi field input, liệt kê phân vùng hợp lệ, không hợp lệ và các giá trị biên trước khi viết case.
    • Viết charter trước mỗi exploratory session và ghi chú trong lúc test, không phải sau đó.
    • Rút gọn bước tái hiện tới mức tối thiểu trước khi gửi bug.
    • Đính kèm bằng chứng có thể kiểm chứng như video, HAR hoặc request ID.

    Dễ sai

    • Viết hàng trăm test case gần giống nhau thay vì áp dụng phân vùng tương đương.
    • Bug report chỉ ghi 'không chạy' mà không có môi trường hay kết quả mong đợi.

    Project chốt chặng: Test suite cho một form đặt phòng

    Dùng một app demo công khai như Restful Booker, thiết kế test case bằng phân vùng tương đương, giá trị biên và một decision table cho quy tắc giá. Chạy hai exploratory session có charter và nộp ít nhất ba bug report theo đúng mẫu, mỗi report tái hiện được trong năm bước trở xuống.

    • Test design
    • Exploratory
    • Bug reports

    Kiểm tra nhanh

    Đã trả lời 0/4 · đúng 0

    Trả lời đúng ít nhất 3/4 câu để đánh dấu đã qua chặng này.

    1. Câu 1/4Cơ bảnTrường tuổi chấp nhận từ 18 đến 65, tính cả hai đầu. Bộ giá trị nào áp dụng boundary value analysis đúng?
    2. Câu 2/4Cơ bảnVì sao pairwise testing giảm mạnh số case mà vẫn bắt được phần lớn bug cấu hình?
    3. Câu 3/4Cơ bảnMột đơn hàng đi qua draft, paid, shipped, delivered và chỉ được hủy trước khi giao. Test nào dễ lộ bug ẩn nhất?
    4. Câu 4/4Cơ bảnTiêu đề bug report nào hữu ích nhất cho developer nhận xử lý?
  3. 03Chặng 03, 2 tuầnWeb, HTTP và DevTools cho testerĐọc được request, response, cookie và console để khoanh vùng bug nằm ở frontend, API hay hạ tầng.
    Từ phía frontend, mình thấy bug report giá trị nhất luôn đến từ các bạn QA biết mở tab Network. Chỉ cần ghi được status code và response body là thời gian debug giảm hẳn.

    Kiến thức cần nắm

    HTTP căn bản
    Nắm method (GET, POST, PUT, PATCH, DELETE), tính idempotent, status code theo nhóm 2xx, 3xx, 4xx, 5xx và các header hay gặp như Content-Type, Authorization, Cache-Control. Biết phân biệt 401 với 403, 404 với 410 giúp bạn chỉ đúng chỗ lỗi.
    Cookie, session, token và CORS
    Hiểu cookie có HttpOnly, Secure, SameSite, khác biệt giữa session cookie và JWT, và vì sao lỗi CORS xuất hiện ở trình duyệt nhưng gọi bằng API client thì vẫn chạy. Đây là nơi nhiều bug đăng nhập, hết hạn phiên và phân quyền ẩn nấp.
    Chrome DevTools cho việc test
    Tab Network để lọc request, xem payload, giả lập mạng chậm và export HAR. Tab Application để xem storage, cookie và service worker. Console để bắt lỗi JavaScript, còn Device Mode và Rendering giúp giả lập viewport, prefers-color-scheme và giảm chuyển động.
    Rendering và trạng thái bất đồng bộ
    App hiện đại render phía client, dữ liệu đến sau, nên có loading, empty, error và stale state. Biết cache của trình duyệt, CDN và các thư viện như TanStack Query hoạt động thế nào giúp bạn giải thích bug 'refresh thì hết'.

    Nên làm

    • Mở DevTools ở mọi phiên test và giữ tab Network với tuỳ chọn Preserve log.
    • Đính kèm status code, request ID và response body vào bug liên quan đến API.
    • Test lại mỗi luồng quan trọng với mạng chậm và khi API trả lỗi.

    Dễ sai

    • Báo lỗi giao diện trong khi nguyên nhân thật là API trả 500.
    • Bỏ qua lỗi đỏ trong Console vì màn hình trông vẫn bình thường.

    Project chốt chặng: Bản đồ request của một luồng

    Chọn luồng đăng nhập rồi thêm vào giỏ hàng của một app demo, ghi lại toàn bộ request bằng HAR và vẽ sơ đồ ai gọi gì, trả gì. Đạt yêu cầu khi bạn chỉ ra được cookie hoặc token nào giữ phiên đăng nhập và mô tả điều gì xảy ra khi API giỏ hàng trả lỗi.

    • HTTP
    • DevTools
    • Debugging

    Kiểm tra nhanh

    Đã trả lời 0/4 · đúng 0

    Trả lời đúng ít nhất 3/4 câu để đánh dấu đã qua chặng này.

    1. Câu 1/4Cơ bảnMột người dùng đã đăng nhập mở trang admin và API trả về 403. Điều đó cho bạn biết gì?
    2. Câu 2/4Cơ bảnMột API call chạy được trong Postman nhưng lỗi CORS trên trình duyệt. Vì sao?
    3. Câu 3/4Cơ bảnTrang danh sách hiển thị 'Chưa có mục nào' với người dùng đã có dữ liệu. Tab Network cho thấy request danh sách trả 500. Bạn nên báo bug thế nào?
    4. Câu 4/4Cơ bảnVì sao tự động retry một PUT thường an toàn hơn retry một POST?

Cốt lõi04–08

  1. 04Chặng 04, 4 tuầnLập trình cho tester với TypeScriptViết được code test sạch bằng TypeScript: hàm, async/await, module, kiểu dữ liệu và một test runner.
    Nhiều bạn tester mình quen học thẳng framework automation mà bỏ qua ngôn ngữ, rồi kẹt ở async/await. Nếu team bạn dùng Python thì cứ theo Python, quan trọng là nắm chắc một ngôn ngữ.

    Kiến thức cần nắm

    Chọn ngôn ngữ: TypeScript hay Python
    TypeScript đi cùng Playwright, k6 và phần lớn frontend nên giúp bạn đọc được code của dev. Python mạnh với pytest, data và công cụ AI. Chọn theo stack của team, vì test nên sống cùng repo và cùng ngôn ngữ với sản phẩm khi có thể.
    Async, Promise và lỗi bất đồng bộ
    Gần như mọi thao tác UI và API trong automation đều bất đồng bộ. Hiểu Promise, async/await, Promise.all và hậu quả của việc quên await (test pass giả hoặc lỗi không đồng bộ) là kỹ năng sống còn.
    Kiểu dữ liệu và cấu trúc code test
    Dùng type cho test data và response giúp bắt lỗi trước khi chạy. Học cách tách helper, builder cho dữ liệu và module, nhưng giữ test dễ đọc theo mẫu Arrange, Act, Assert. Test là code production của QA, cần review và refactor như vậy.
    Test runner và assertion
    Làm quen với một unit test runner như Vitest hoặc pytest để hiểu describe, hooks, assertion, mock và snapshot. Đọc được unit test của dev cũng giúp bạn biết phần nào đã được phủ để không test trùng ở cấp E2E.
    Git và quy trình review
    Branch, commit nhỏ, pull request và giải quyết conflict là việc hằng ngày của SDET. Biết đọc diff của dev giúp bạn đoán vùng rủi ro mới thay đổi để tập trung test.

    Nên làm

    • Bật strict mode trong TypeScript và lint rule cấm promise không được await.
    • Giữ mỗi test độc lập, không dựa vào thứ tự chạy.
    • Gửi code test qua pull request và nhờ developer review như code sản phẩm.

    Dễ sai

    • Copy paste code test từ tutorial mà không hiểu async, dẫn đến test pass giả.
    • Trừu tượng hoá quá sớm khiến test khó đọc hơn chính tính năng.

    Project chốt chặng: Thư viện tính giá có unit test

    Viết một module TypeScript tính tổng giỏ hàng với mã giảm giá và thuế, rồi viết unit test bằng Vitest dựa trên bảng quyết định từ stage 02. Đạt yêu cầu khi test chạy trong CI, có case cho giá trị biên và không có promise nào bị bỏ quên await.

    • TypeScriptTypeScript
    • Python
    • VitestVitest

    Kiểm tra nhanh

    Đã trả lời 0/4 · đúng 0

    Trả lời đúng ít nhất 3/4 câu để đánh dấu đã qua chặng này.

    1. Câu 1/4Trung cấpTrong một test Playwright, page.click('#save'); expect(page.getByText('Saved')).toBeVisible(); không có await. Vấn đề là gì?
    2. Câu 2/4Trung cấpPhần setup tạo ba test user độc lập bằng await Promise.all([...]). Cách này mang lại gì?
    3. Câu 3/4Trung cấpTest B chỉ pass khi test A chạy trước, vì A tạo user mà B dùng để đăng nhập. Hệ quả là gì?
    4. Câu 4/4Trung cấpMột pull request sửa helper định dạng ngày dùng chung cho hóa đơn và báo cáo. Bạn nên tập trung test ở đâu?
  2. 05Chặng 05, 4 tuầnAPI testing và contract testingTest API thủ công lẫn tự động, validate schema và giữ hợp đồng giữa frontend và backend bằng contract test.
    Phần lớn bug mình gặp khi tích hợp đến từ việc backend đổi shape của response mà frontend không biết. Contract testing là thứ mình ước team đã dùng sớm hơn.

    Kiến thức cần nắm

    Postman và Bruno
    Postman mạnh về collaboration trên cloud, workspace và mock server. Bruno lưu collection thành file text ngay trong repo nên review và version bằng Git rất tự nhiên, phù hợp team muốn mọi thứ nằm cạnh code. Dù dùng tool nào, hãy học biến môi trường, script trước và sau request, và chạy collection từ CLI trong CI.
    Thiết kế test cho API
    Ngoài happy path, test validation (400, 422), xác thực và phân quyền (401, 403, truy cập tài nguyên của người khác), idempotency, phân trang, rate limit và xử lý đồng thời. Lỗi phân quyền theo đối tượng (BOLA) là rủi ro hàng đầu trong OWASP API Security Top 10.
    Schema validation
    Dùng OpenAPI làm nguồn sự thật và validate response bằng JSON Schema (Ajv) hoặc Zod để bắt thay đổi kiểu, field bị thiếu hay null bất ngờ. Kiểm tra schema rẻ và bắt được nhiều lỗi tích hợp hơn việc so sánh từng giá trị.
    Contract testing với Pact
    Pact theo hướng consumer-driven: consumer ghi lại kỳ vọng thành file pact, provider verify lại trong pipeline của mình. Pact Broker lưu hợp đồng theo version và lệnh can-i-deploy cho biết hai bên có tương thích trước khi release. Contract test thay thế được nhiều E2E chậm chỉ để kiểm tra tích hợp.
    API test bằng code
    Playwright có request fixture (APIRequestContext) để gọi API trong cùng test runner, rất tiện để seed dữ liệu hoặc test API song song với UI. Kết hợp với schema validation và test data builder, bạn có bộ API test nhanh, ổn định hơn E2E nhiều lần.

    Nên làm

    • Lưu collection API trong repo và chạy chúng trong CI ở mỗi pull request.
    • Validate schema của mọi response trước khi assert giá trị cụ thể.
    • Test phân quyền bằng cách dùng token của user A để truy cập dữ liệu của user B.
    • Chạy can-i-deploy trước khi release nếu dùng contract testing.

    Dễ sai

    • Chỉ test status 200 mà không kiểm tra body và schema.
    • Dùng contract test để kiểm tra logic nghiệp vụ của provider, trong khi nó chỉ nên khoá hình dạng tương tác.

    Project chốt chặng: Bộ API test có contract

    Viết collection Bruno và một bộ API test bằng Playwright cho Restful Booker hoặc API của chính bạn, có validate schema bằng Zod hoặc Ajv. Thêm một Pact consumer test cho một endpoint. Đạt yêu cầu khi cả hai chạy trong CI và có ít nhất ba case cho lỗi xác thực và phân quyền.

    • API
    • Pact
    • Bruno
    • Schema

    Kiểm tra nhanh

    Đã trả lời 0/4 · đúng 0

    Trả lời đúng ít nhất 3/4 câu để đánh dấu đã qua chặng này.

    1. Câu 1/4Trung cấpBạn test lỗ hổng broken object level authorization (BOLA) trên GET /orders/{id} thế nào?
    2. Câu 2/4Trung cấpVì sao nên validate mỗi response theo OpenAPI schema trước khi assert các giá trị cụ thể?
    3. Câu 3/4Trung cấpMột contract test Pact giữa web app và orders API nên kiểm điều gì?
    4. Câu 4/4Trung cấpTrước khi release phiên bản consumer mới, team chạy can-i-deploy với Pact Broker. Lệnh này trả lời câu hỏi gì?
  3. 06Chặng 06, 5 tuầnUI automation với PlaywrightXây được bộ E2E test bằng Playwright ổn định, dễ đọc, chạy song song và debug được bằng trace.
    Đây là phần mình tự tay làm nhiều nhất. Bài học lớn nhất là test flaky gần như luôn do mình viết sai cách chờ hoặc phụ thuộc dữ liệu, rất hiếm khi do Playwright.

    Kiến thức cần nắm

    Locator theo hướng người dùng
    Ưu tiên getByRole, getByLabel, getByText rồi mới đến getByTestId, tránh CSS selector dài và XPath gắn với cấu trúc DOM. Locator theo role vừa bền vừa gián tiếp kiểm tra accessibility. Locator trong Playwright là lazy và strict, nên khớp nhiều phần tử sẽ báo lỗi thay vì chọn bừa.
    Auto-waiting và web-first assertion
    Playwright tự chờ phần tử visible, enabled và stable trước khi thao tác. Assertion như toBeVisible hay toHaveText tự retry đến khi timeout. Vì vậy không cần waitForTimeout; nếu phải sleep cứng, đó là dấu hiệu test đang sai.
    Fixtures và tách trạng thái
    test.extend cho phép tạo fixture như user đã đăng nhập, dữ liệu seed hay page object, có setup và teardown rõ ràng. Dùng setup project kết hợp storageState để đăng nhập một lần rồi tái sử dụng. Mỗi test chạy trong browser context riêng nên độc lập và chạy song song được.
    Page object và các lựa chọn khác
    Page Object Model gom locator và hành động theo trang, hợp với bộ test lớn nhưng dễ phình thành lớp trừu tượng khó đọc. Các lựa chọn khác là fixture theo tính năng, helper theo hành động người dùng hoặc giữ locator ngay trong test khi test còn ít. Chọn mức trừu tượng vừa đủ cho kích thước suite.
    Network mocking và thời gian
    page.route cho phép mock hoặc chỉnh response để test trạng thái lỗi, empty và loading mà backend khó tái hiện. HAR replay giúp chạy test với dữ liệu ghi sẵn. page.clock kiểm soát thời gian cho các tính năng phụ thuộc ngày giờ như hết hạn phiên hay countdown.
    Xử lý test flaky
    Bật trace ở lần retry đầu tiên, mở Trace Viewer để xem DOM, network và console từng bước. Dùng --repeat-each để tái hiện flaky ở local. Nguyên nhân phổ biến là race với dữ liệu, phụ thuộc thứ tự test, animation và môi trường dùng chung; retry chỉ là băng cá nhân, cần cách ly và sửa tận gốc.

    Nên làm

    • Dùng getByRole làm locator mặc định và thêm data-testid chỉ khi không có cách nào tốt hơn.
    • Không dùng waitForTimeout; dựa vào web-first assertion.
    • Đăng nhập qua setup project và storageState thay vì qua UI ở mỗi test.
    • Cấu hình trace: 'on-first-retry' và theo dõi tỉ lệ flaky theo từng test.
    • Quarantine test flaky có owner và hạn sửa, không để nó âm thầm bị skip mãi.

    Dễ sai

    • Viết E2E cho mọi trường hợp biên trong khi chúng nên nằm ở unit hoặc API test.
    • Để các test chia sẻ cùng một tài khoản và dữ liệu, gây flaky khi chạy song song.
    • Tăng retry lên cao để pipeline xanh, che giấu bug race condition thật.

    Project chốt chặng: E2E suite cho một cửa hàng demo

    Viết 10 đến 15 test Playwright cho Sauce Demo hoặc app của bạn, bao gồm đăng nhập qua storageState, checkout và các trạng thái lỗi bằng page.route. Đạt yêu cầu khi suite chạy song song, không có waitForTimeout và chạy --repeat-each=10 không có lần fail nào.

    Kiểm tra nhanh

    Đã trả lời 0/4 · đúng 0

    Trả lời đúng ít nhất 3/4 câu để đánh dấu đã qua chặng này.

    1. Câu 1/4Trung cấpawait page.getByRole('button', { name: 'Delete' }).click() chạy trên trang có hai nút Delete khớp. Điều gì xảy ra?
    2. Câu 2/4Trung cấpMột test bị flaky vì toast 'Saved' đôi khi xuất hiện sau 2 giây. Cách sửa nào đúng?
    3. Câu 3/4Trung cấpMỗi test trong bộ 300 test đều đăng nhập qua UI trước. Cải tiến được khuyến nghị là gì?
    4. Câu 4/4Trung cấpVì sao tăng retries để giữ pipeline xanh là thói quen rủi ro?
  4. 07Chặng 07, 3 tuầnCI, báo cáo, dữ liệu test và visual regressionĐưa test vào pipeline với sharding, báo cáo rõ ràng, dữ liệu test cách ly và kiểm tra giao diện bằng screenshot.
    Test chỉ có giá trị khi chạy tự động và kết quả được người khác đọc. Mình từng có bộ test chạy tốt ở máy nhưng không ai xem báo cáo, coi như không có.

    Kiến thức cần nắm

    Test trong pipeline
    Chạy test nhanh (lint, unit, API, contract) ở mỗi pull request, E2E smoke trước khi merge và bộ đầy đủ theo lịch hoặc trước release. Dùng container chính thức của Playwright để đồng nhất trình duyệt giữa local và CI. Cache dependency và chỉ cài trình duyệt cần dùng để pipeline nhanh.
    Song song hoá và sharding
    Playwright chạy song song theo worker trong một máy và chia shard qua nhiều máy bằng --shard. Dùng blob reporter ở mỗi shard rồi merge-reports để có một báo cáo HTML duy nhất. Test phải độc lập dữ liệu thì mới song song hoá an toàn.
    Báo cáo và tín hiệu
    Báo cáo cần trả lời nhanh: fail ở đâu, có phải flaky không, có trace hay video không. Đẩy kết quả JUnit vào CI để hiện ngay trên pull request, và theo dõi xu hướng thời gian chạy, tỉ lệ flaky theo thời gian thay vì chỉ xem một lần chạy.
    Quản lý dữ liệu test
    Tạo dữ liệu qua API hoặc factory cho từng test thay vì dùng chung một database được sửa tay. Faker với seed cố định cho dữ liệu ngẫu nhiên mà vẫn tái hiện được. Testcontainers dựng database tạm thời cho integration test, và luôn có chiến lược dọn dẹp hoặc dữ liệu có namespace riêng.
    Visual regression
    toHaveScreenshot của Playwright so sánh pixel với ảnh baseline, nên chụp ở môi trường cố định (container, font, viewport) và mask phần động như thời gian hay avatar. Với component, có thể test visual qua Storybook. ARIA snapshot (toMatchAriaSnapshot) là lựa chọn bổ sung, kiểm tra cấu trúc thay vì pixel nên ít nhiễu hơn.

    Nên làm

    • Tách pipeline thành tầng nhanh và tầng đầy đủ, chặn merge bằng tầng nhanh.
    • Upload trace, video và báo cáo HTML làm artifact cho mọi lần chạy fail.
    • Sinh dữ liệu riêng cho từng test và không phụ thuộc dữ liệu có sẵn trên staging.
    • Cập nhật baseline screenshot qua pull request có review, không cập nhật hàng loạt mù quáng.

    Dễ sai

    • Chụp baseline visual trên máy local rồi so sánh trên CI, dẫn đến khác biệt font và render.
    • Để một bộ E2E chạy 40 phút chặn mọi pull request.

    Project chốt chặng: Pipeline test hoàn chỉnh

    Cấu hình GitHub Actions chạy API test, contract test và E2E Playwright chia 3 shard, merge thành một báo cáo HTML và upload trace khi fail. Thêm 3 visual test có mask phần động. Đạt yêu cầu khi pipeline dưới 10 phút và hai lần chạy liên tiếp cho cùng kết quả.

    Kiểm tra nhanh

    Đã trả lời 0/4 · đúng 0

    Trả lời đúng ít nhất 3/4 câu để đánh dấu đã qua chặng này.

    1. Câu 1/4Trung cấpBạn chia bộ test Playwright ra 4 máy CI bằng --shard. Làm sao có một HTML report duy nhất?
    2. Câu 2/4Trung cấpScreenshot test pass ở máy local nhưng fail trên CI vì khác biệt nhỏ về font và khử răng cưa. Nguyên nhân khả dĩ nhất là gì?
    3. Câu 3/4Trung cấpTest fail trên staging vì có người sửa tài khoản test dùng chung. Cách nào khắc phục tốt nhất?
    4. Câu 4/4Trung cấpVì sao chặn merge pull request bằng tầng test nhanh, còn bộ E2E đầy đủ chạy theo lịch hoặc trước release?
  5. 08Chặng 08, 3 tuầnKiểm thử mobile căn bảnHiểu đặc thù của test mobile và tự động hoá được vài luồng chính bằng Maestro hoặc Appium.
    Mình chỉ đứng cạnh các bạn mobile và QA mobile, nhưng đủ để thấy mobile có cả một lớp rủi ro mà web không có: quyền, mạng chập chờn, app bị kill giữa chừng.

    Kiến thức cần nắm

    Đặc thù của mobile
    Phân mảnh thiết bị và phiên bản OS, quyền truy cập (camera, vị trí, thông báo), vòng đời app (background, bị kill, khôi phục), deep link, mạng yếu và offline. Ma trận thiết bị nên dựa trên analytics người dùng thật, không phải danh sách máy đẹp nhất.
    Maestro
    Maestro viết flow bằng YAML, chạy trên release build mà không cần instrument code, có sẵn cơ chế chờ và retry nên ít flaky. Rất phù hợp để có smoke test nhanh cho app React Native, Flutter hay native. Khi logic phức tạp, YAML có thể trở nên khó bảo trì.
    Appium
    Appium dùng giao thức WebDriver với các driver tách riêng như UiAutomator2 cho Android và XCUITest cho iOS, viết test bằng nhiều ngôn ngữ. Linh hoạt và phổ biến trong doanh nghiệp, đổi lại setup phức tạp hơn và cần chú ý chiến lược chờ để tránh flaky.
    Công cụ native và device cloud
    Espresso (Android) và XCUITest (iOS) nhanh và ổn định nhất nhưng gắn với từng nền tảng, thường do dev mobile viết. Emulator và simulator cho phần lớn test, còn device cloud hoặc máy thật cho kiểm tra hiệu năng, cảm biến và các lỗi riêng của hãng.

    Nên làm

    • Đặt accessibility identifier hoặc testID ổn định cho các phần tử cần tự động hoá.
    • Test các luồng gián đoạn như cuộc gọi đến, chuyển sang background và mất mạng.
    • Chọn ma trận thiết bị từ dữ liệu người dùng thật và xem lại mỗi quý.

    Dễ sai

    • Chỉ test trên emulator mới nhất mà bỏ qua máy cấu hình thấp người dùng thật đang dùng.
    • Bê nguyên cách viết test web sang mobile mà không tính đến vòng đời app và quyền.

    Project chốt chặng: Smoke test mobile bằng Maestro

    Viết 3 flow Maestro cho một app mẫu: mở app, đăng nhập, thực hiện một hành động chính và xử lý hộp thoại xin quyền. Đạt yêu cầu khi flow chạy được trên emulator Android trong CI và bạn viết được một trang so sánh khi nào nên dùng Appium thay thế.

    • Mobile
    • Maestro
    • Appium

    Kiểm tra nhanh

    Đã trả lời 0/4 · đúng 0

    Trả lời đúng ít nhất 3/4 câu để đánh dấu đã qua chặng này.

    1. Câu 1/4Trung cấpBạn nên chọn thiết bị cho ma trận test mobile thế nào?
    2. Câu 2/4Trung cấpNgười dùng điền một form dài, chuyển sang app camera rồi quay lại thì form trống trơn. Test nào sẽ bắt được lỗi này?
    3. Câu 3/4Trung cấpVì sao Maestro hợp với smoke test nhanh trên app React Native, Flutter và native?
    4. Câu 4/4Trung cấpTest Appium của bạn vỡ mỗi khi designer chỉnh câu chữ hoặc layout. Cách khắc phục hiệu quả nhất là gì?

Nâng cao09–10

  1. 09Chặng 09, 5 tuầnHiệu năng, accessibility và bảo mậtThiết kế và chạy được load test với k6, kiểm tra accessibility tự động lẫn thủ công và thực hiện các kiểm tra bảo mật cơ bản.
    Là frontend dev, mình học accessibility trước rồi mới thấy QA là người giữ nó không bị thoái lui. Phần hiệu năng và bảo mật mình vẫn đang học, và thấy chúng cần tư duy khác hẳn test chức năng.

    Kiến thức cần nắm

    Load testing với k6
    k6 viết kịch bản bằng JavaScript, cấu hình scenarios với executor như ramping-vus hay constant-arrival-rate, và đặt thresholds (ví dụ p95 dưới một ngưỡng, tỉ lệ lỗi dưới 1%) để test fail tự động. Phân biệt smoke, load, stress, spike và soak test, mỗi loại trả lời một câu hỏi khác nhau.
    Đọc kết quả hiệu năng
    Nhìn percentile (p95, p99) thay vì trung bình, tương quan với CPU, memory, connection pool và trace phía server. Chạy trên môi trường giống production về cấu hình, và với frontend, theo dõi Core Web Vitals (LCP, INP, CLS) qua Lighthouse và dữ liệu người dùng thật.
    Accessibility testing
    Chạy axe-core qua @axe-core/playwright để bắt lỗi tự động như thiếu label, contrast, ARIA sai, nhưng công cụ tự động chỉ phát hiện được một phần vấn đề. Phần còn lại cần test thủ công: chỉ dùng bàn phím, focus order, screen reader (NVDA, VoiceOver) và zoom 200%. Chuẩn tham chiếu là WCAG 2.2 mức AA, và European Accessibility Act đã khiến đây thành yêu cầu pháp lý với nhiều sản phẩm.
    Bảo mật cơ bản cho tester
    Nắm OWASP Top 10 và OWASP API Security Top 10: broken access control, injection, lỗi xác thực, cấu hình sai. Thử IDOR bằng cách đổi ID trong request, kiểm tra header bảo mật, và chạy quét DAST như ZAP baseline trong CI. Bảo mật sâu là việc của chuyên gia, nhưng tester bắt được rất nhiều lỗi phân quyền.
    Chaos và độ bền
    Test hành vi khi phụ thuộc chậm hoặc chết: timeout, retry, circuit breaker và thông báo lỗi cho người dùng. Bắt đầu nhỏ bằng mock lỗi mạng trong Playwright hoặc tắt một service ở staging trước khi nghĩ tới chaos engineering đầy đủ.

    Nên làm

    • Định nghĩa mục tiêu hiệu năng bằng thresholds trong k6 trước khi chạy test.
    • Thêm kiểm tra axe vào E2E cho các trang chính và chặn merge khi có vi phạm mức serious.
    • Kiểm tra mọi tính năng mới bằng bàn phím trước khi coi là xong.
    • Chỉ chạy load test và quét bảo mật trên môi trường bạn được phép.

    Dễ sai

    • Đọc thời gian phản hồi trung bình và bỏ qua đuôi p99.
    • Nghĩ rằng điểm axe sạch nghĩa là trang đã accessible.
    • Chạy load test vào production hoặc API bên thứ ba mà không báo trước.

    Project chốt chặng: Báo cáo chất lượng phi chức năng

    Viết kịch bản k6 với hai scenario (load và spike) và thresholds cho một API của bạn, thêm kiểm tra axe vào ba trang chính và chạy ZAP baseline scan trong CI. Đạt yêu cầu khi có một trang báo cáo nêu rõ ngưỡng, kết quả, ba vấn đề lớn nhất và đề xuất sửa.

    Kiểm tra nhanh

    Đã trả lời 0/4 · đúng 0

    Trả lời đúng ít nhất 3/4 câu để đánh dấu đã qua chặng này.

    1. Câu 1/4Nâng caoMột load test báo thời gian phản hồi trung bình 180 ms và p99 là 4 s. Bạn nên kết luận gì?
    2. Câu 2/4Nâng caoTùy chọn k6 nào làm lần chạy tự fail khi latency bị thoái lui?
    3. Câu 3/4Nâng caoaxe báo không có vi phạm nào ở trang đăng ký. Vì sao bạn chưa thể nói trang đã accessible?
    4. Câu 4/4Nâng caoKhi đăng nhập bằng tài khoản của bạn, test nào kiểm lỗ hổng IDOR?
  2. 10Chặng 10, 5 tuầnQuality engineering và AI trong testingĐo chất lượng bằng số liệu có ý nghĩa, test an toàn trong production và dùng AI để tăng tốc test cũng như đánh giá tính năng AI.
    Phần AI mình tiếp cận từ phía tích hợp LLM vào sản phẩm, nên mình thấy rõ: test một tính năng AI khó hơn nhiều so với để AI viết test. Cả hai đều cần con người giữ phán đoán cuối cùng.

    Kiến thức cần nắm

    Số liệu chất lượng
    Theo dõi escaped defects, tỉ lệ flaky, thời gian feedback của pipeline và các chỉ số DORA như change failure rate, thời gian khôi phục. Code coverage chỉ cho biết dòng nào chưa được chạy, không nói test có tốt hay không. Chọn ít số liệu, gắn với quyết định cụ thể.
    Observability và testing in production
    OpenTelemetry giúp nối trace từ frontend tới backend, nên bug report có thể kèm trace ID thay vì mô tả mơ hồ. Synthetic monitoring chạy các luồng chính trên production theo lịch, kết hợp SLO và alert theo error budget. Testing in production không thay thế test trước release, mà bắt những gì staging không bao giờ tái hiện được.
    Feature flag và release an toàn
    Feature flag tách deploy khỏi release, cho phép canary, rollout theo phần trăm và kill switch. OpenFeature là chuẩn mở để không bị khoá vào một nhà cung cấp. QA cần test cả hai trạng thái của flag, tổ hợp flag quan trọng, và có kế hoạch dọn flag cũ.
    Sinh test bằng LLM và agent
    Playwright có test agents (planner, generator, healer) chạy trong các agent loop như VS Code, Claude Code, và Playwright MCP cho phép agent điều khiển trình duyệt qua accessibility tree. Chúng tăng tốc phần viết khung test, nhưng con người vẫn phải quyết định test cái gì và review assertion, vì AI hay sinh test đi theo hành vi hiện tại kể cả khi hành vi đó sai.
    Self-healing test
    Self-healing tự sửa locator hoặc bước khi UI đổi, giảm công bảo trì. Rủi ro là nó che mất bug thật, ví dụ nút bị đổi nhãn sai vẫn được coi là đúng. Hãy coi mọi thay đổi do healer đề xuất như một pull request cần review, không tự động merge.
    Đánh giá tính năng AI
    Output của LLM không tất định nên assertion so khớp chính xác không đủ. Cần bộ eval dataset từ case thật, chấm bằng rule, so sánh ngữ nghĩa hoặc LLM-as-judge đã được hiệu chỉnh với nhãn của người, và chạy eval như regression test trong CI với công cụ như promptfoo. Đừng quên red-teaming: prompt injection, lộ dữ liệu và hành vi ngoài phạm vi.

    Nên làm

    • Đính kèm trace ID hoặc request ID vào mọi bug xảy ra trên môi trường có observability.
    • Test mỗi feature flag ở cả trạng thái bật và tắt trước khi rollout.
    • Review mọi test và mọi bản sửa do AI sinh ra như code của một đồng đội mới.
    • Xây eval dataset từ lỗi thật của người dùng và mở rộng nó mỗi khi có sự cố.

    Dễ sai

    • Đặt KPI theo coverage hoặc số bug tìm được, khiến team tối ưu con số thay vì chất lượng.
    • Để healer tự sửa test mà không ai xem, biến bug thật thành test xanh.
    • Đánh giá tính năng AI bằng vài prompt thử tay rồi kết luận là ổn.

    Project chốt chặng: Quality dashboard và bộ eval

    Dùng Playwright test agents để sinh thêm test cho app ở stage 06, review và ghi lại bao nhiêu phần phải sửa tay. Xây một bộ eval 30 case cho một tính năng LLM nhỏ (ví dụ tóm tắt hoặc phân loại) chạy trong CI. Đạt yêu cầu khi có một dashboard đơn giản hiển thị tỉ lệ flaky, thời gian pipeline và điểm eval theo thời gian.

    • Quality metrics
    • Observability
    • AI testing
    • Evals

    Kiểm tra nhanh

    Đã trả lời 0/4 · đúng 0

    Trả lời đúng ít nhất 3/4 câu để đánh dấu đã qua chặng này.

    1. Câu 1/4Nâng caoVì sao code coverage là KPI yếu để đo chất lượng test?
    2. Câu 2/4Nâng caoMột trang checkout mới được phát hành sau feature flag, rollout cho 10% người dùng. QA phải test gì trước khi rollout?
    3. Câu 3/4Nâng caoMột công cụ self-healing tự cập nhật locator sau khi nhãn nút đổi từ 'Pay' thành 'Pya'. Vì sao các bản sửa như vậy phải qua review?
    4. Câu 4/4Nâng caoBạn nên test tính năng trả lời hỗ trợ dùng LLM thế nào trước mỗi release?

Những gì đang quan trọng lúc này và hướng đi trong vài năm tới.

Hiện tại

  • Playwright là mặc định cho web E2E

    Với dự án web mới, Playwright gần như là lựa chọn mặc định nhờ auto-waiting, trace và chạy song song sẵn có. Selenium và Cypress vẫn còn nhiều trong các codebase cũ, nên biết đọc chúng vẫn có ích.

  • AI agent viết và sửa test

    Test agents của Playwright và Playwright MCP đưa việc sinh, chạy, sửa test vào trong editor và agent loop. Kỹ năng quan trọng chuyển sang thiết kế test, viết yêu cầu rõ ràng và review output của AI.

  • QA thành quality engineer

    Developer ngày càng tự viết test, còn QA tập trung vào chiến lược, hạ tầng test, exploratory testing và coaching. Ranh giới giữa SDET, QA và platform engineering mờ dần.

  • Accessibility thành yêu cầu bắt buộc

    European Accessibility Act và các quy định tương tự khiến WCAG 2.2 AA trở thành tiêu chí release ở nhiều sản phẩm. Team cần cả kiểm tra tự động trong CI lẫn kiểm tra thủ công định kỳ.

Sắp tới

  • Eval là một nhánh của QA

    Khi ngày càng nhiều sản phẩm có tính năng LLM và agent, đánh giá output không tất định sẽ trở thành kỹ năng QA cốt lõi. Hãy học thiết kế eval dataset, LLM-as-judge và red-teaming từ bây giờ.

  • Agentic testing ở quy mô lớn

    Agent sẽ khám phá app, đề xuất test và tự bảo trì suite ở mức nhiều hơn hiện nay. Giá trị của tester sẽ nằm ở việc định nghĩa rủi ro, oracle (thế nào là đúng) và kiểm soát để AI không hợp thức hoá bug.

  • Chất lượng dựa trên tín hiệu production

    Observability, feature flag và progressive delivery khiến dữ liệu production trở thành một phần của chiến lược test. Học OpenTelemetry, SLO và cách đọc trace sẽ giúp tester làm việc ngang hàng với SRE.

  • Hợp đồng thay thế E2E chậm

    Contract testing, schema-first API và component test sẽ gánh nhiều phần kiểm tra tích hợp, E2E chỉ giữ lại cho luồng quan trọng nhất. Chuẩn bị bằng cách nắm OpenAPI, Pact và tư duy chọn đúng cấp độ test.

Đi hết roadmap, bạn sẽ

  • Bạn có thể lập chiến lược test dựa trên rủi ro và giải thích vì sao mỗi test nằm ở cấp độ đó.
  • Bạn có thể thiết kế test case bằng phân vùng tương đương, giá trị biên, decision table, state transition và chạy exploratory session có charter.
  • Bạn có thể viết API test có schema validation và contract test với Pact chạy trong CI.
  • Bạn có thể xây và bảo trì bộ E2E Playwright ổn định, chạy song song, debug flaky bằng trace.
  • Bạn có thể chạy load test với k6, kiểm tra accessibility theo WCAG 2.2 và các kiểm tra bảo mật cơ bản.
  • Bạn có thể dùng AI agent để sinh test một cách có kiểm soát và xây bộ eval cho tính năng LLM.
  • Bạn có thể đo chất lượng bằng số liệu có ý nghĩa và dùng observability, feature flag để giảm rủi ro release.

Bài viết liên quan

Tất cả bài viết

TypeScript ở tầng type cho API contract không thể dùng sai

Conditional type và infer, key remapping, template literal type biến "/users/:id/posts/:postId" thành params có type, một fetch client suy ra từ route map, lỗi có type, branded ID, satisfies và const type parameter, cầu nối Zod để type không nói dối — và khi nào nên dừng.

Công cụ & quy trình18 phút

Các role khác

Roadmap

Frontend Engineer

Role chính của mình

Xây giao diện web nhanh, dễ tiếp cận và bền vững khi sản phẩm lẫn team cùng lớn lên

10 chặng, 51 chủ đề, ~34 tuần

Thiết kế, xây dựng và vận hành API, dữ liệu và service phía sau mỗi sản phẩm

10 chặng, 52 chủ đề, ~37 tuần

Xây app iOS và Android mượt, chạy được khi mất mạng và phát hành an toàn

10 chặng, 50 chủ đề, ~34 tuần

Xây hạ tầng, pipeline và nền tảng để team ship nhanh, chạy ổn định, an toàn

10 chặng, 56 chủ đề, ~42 tuần

Xây sản phẩm trên nền LLM: từ gọi API, RAG, agent đến eval và vận hành production

10 chặng, 58 chủ đề, ~31 tuần