Menu
ESC

Nhập từ khóa để tìm kiếm

↑↓ Di chuyển
Enter Mở
ESC Đóng

Đang tải...

API testing strategy: cho BA và QA

API and Technical Fundamentals cho BA Bài 48/60

Mở đầu — vì sao bài này quan trọng

Hãy hình dung tình huống này: đội phát triển của bạn vừa ship một API mới cho tính năng "đặt hàng". Demo chạy ngon lành, ai cũng vỗ tay. Hai tuần sau, khách hàng phản ánh rằng khi họ đặt hàng với số lượng âm (-5 sản phẩm), hệ thống vẫn chấp nhận và còn... hoàn tiền cho họ. Hóa ra API chưa từng được test với dữ liệu "xấu". Lúc này, ai là người bị hỏi đầu tiên trong buổi họp? Thường không phải lập trình viên, mà là BA — người đã viết spec mà quên ghi rõ ràng "số lượng phải lớn hơn 0".

Đây chính là lý do một BA hiện đại cần hiểu về API testing strategy (chiến lược kiểm thử API). Bạn không cần phải tự tay viết toàn bộ test tự động như một QA engineer, nhưng bạn phải hiểu: API nào cần test gì, ở mức độ nào, và quan trọng nhất — làm sao để acceptance criteria (tiêu chí chấp nhận) bạn viết ra có thể kiểm chứng được bằng test thật. Một BA biết tư duy theo hướng kiểm thử sẽ viết spec rõ ràng hơn, ít gây tranh cãi hơn, và giảm đáng kể số bug lọt ra production.

Trong bài này, chúng ta sẽ tập trung vào chiến lược — cách phân tầng test, cách phối hợp giữa BA và QA, cách đọc và đánh giá độ phủ test — chứ không đi sâu vào cú pháp công cụ (Postman, curl đã có bài riêng) hay từng loại test case kỹ thuật. Mục tiêu là sau bài này, bạn có thể ngồi vào một buổi họp "test planning" và đóng góp ý kiến có trọng lượng.

Khái niệm cốt lõi

Test Pyramid — kim tự tháp kiểm thử

Hình ảnh nền tảng nhất bạn cần thuộc lòng là Test Pyramid:

        /\
       /E2E\          ← Ít, chậm, dễ vỡ (giả lập người dùng thật)
      /------\
     / Integ. \       ← API tests nằm ở đây (vừa phải)
    /----------\
   /    Unit    \      ← Nhiều, nhanh, rẻ (test từng hàm nhỏ)
  /--------------\

Ý tưởng của kim tự tháp: càng lên cao, test càng giống thực tế người dùng nhưng càng chậm, đắt và dễ hỏng (brittle). Càng xuống đáy, test càng nhanh, rẻ, ổn định nhưng càng xa thực tế.

  • Unit test (đáy): kiểm tra một hàm/đơn vị code riêng lẻ, ví dụ hàm tinhThue(gia). Đây là việc của lập trình viên, BA hiếm khi đụng tới.
  • Integration / API test (giữa): kiểm tra một endpoint API hoạt động đúng khi gọi thật — gửi request, nhận response, kiểm tra status code và dữ liệu trả về. Đây là tầng BA quan tâm nhất vì nó ánh xạ trực tiếp tới yêu cầu nghiệp vụ.
  • E2E test (đỉnh): kiểm tra cả luồng từ giao diện đến database, ví dụ "người dùng đăng nhập → thêm sản phẩm vào giỏ → thanh toán → nhận email". Rất giống thực tế nhưng chạy chậm và hay "flaky" (lúc đậu lúc rớt do mạng, do thời gian chờ).
Bài học chiến lược: đừng dồn mọi thứ lên đỉnh. Nhiều đội sai lầm khi viết hàng trăm test E2E cho từng quy tắc nghiệp vụ nhỏ — kết quả là bộ test chạy 3 tiếng và hay đỏ ngẫu nhiên đến mức không ai tin nữa. Phần lớn quy tắc nghiệp vụ nên được kiểm tra ở tầng API test, vốn nhanh và đáng tin hơn nhiều.

Bốn loại kiểm thử API mà BA cần phân biệt

Khi nói "test API", thực ra có nhiều khía cạnh khác nhau, và BA cần biết cái nào liên quan đến yêu cầu nào:

  • Functional testing (kiểm thử chức năng): API có làm đúng việc nó phải làm không? Gửi đơn hàng hợp lệ thì trả về 201 Created kèm order_id. Đây là tầng gần với acceptance criteria nhất.
  • Contract testing (kiểm thử hợp đồng): API có tuân thủ đúng "hợp đồng" đã thống nhất không — đúng tên trường, đúng kiểu dữ liệu, đúng status code như trong tài liệu OpenAPI/Swagger? Cực kỳ quan trọng khi nhiều đội cùng tích hợp.
  • Performance testing (kiểm thử hiệu năng): API chịu tải được bao nhiêu request/giây? Thời gian phản hồi p95 (95% request nhanh hơn ngưỡng nào)? Liên quan trực tiếp tới SLA.
  • Security testing (kiểm thử bảo mật): API có chặn truy cập trái phép, có chống injection không? (Chủ đề OWASP API Top 10 có bài riêng, ở đây chỉ cần biết nó là một nhánh trong chiến lược.)
BA không cần thực hiện cả bốn, nhưng khi viết spec, bạn nên ghi rõ những kỳ vọng thuộc các nhóm này để QA có cơ sở thiết kế test.

Test case "happy path" và "sad path"

Đây là khái niệm BA dùng được ngay:

  • Happy path (đường vui): luồng lý tưởng, dữ liệu hợp lệ, mọi thứ suôn sẻ. Ví dụ: đặt hàng 2 sản phẩm còn hàng, thanh toán thành công.
  • Sad path / edge case (đường buồn / trường hợp biên): dữ liệu sai, thiếu trường, vượt giới hạn, hết hàng, token hết hạn, gọi hai lần liên tiếp...
Một quan sát kinh điển trong nghề: lập trình viên thích test happy path, vì code họ viết để chạy đúng luồng đó. Bug thực tế hầu hết nằm ở sad path. Vai trò vàng của BA là liệt kê đầy đủ sad path trong acceptance criteria, vì bạn là người hiểu nghiệp vụ nhất — bạn biết "số lượng không được âm", "mã giảm giá hết hạn thì sao", "khách chưa xác thực email thì có được đặt hàng không".

Định nghĩa "test data" và môi trường

Một chiến lược test tốt phải trả lời: test chạy trên môi trường nào (dev, staging, production) và với dữ liệu nào? BA cần nắm khái niệm này vì nó ảnh hưởng tới việc nghiệm thu (UAT — User Acceptance Testing). Ví dụ, bạn không thể test luồng thanh toán thật bằng thẻ thật trên production — phải dùng sandbox (môi trường giả lập) của cổng thanh toán với thẻ test.

Tình huống thực tế

Tình huống 1: Tiki và quy tắc tồn kho bị bỏ sót

Giả định một đội tại sàn thương mại điện tử lớn (lấy bối cảnh kiểu Tiki) xây API POST /orders. BA viết acceptance criteria khá đầy đủ cho happy path: đặt hàng thành công trả về 201, trừ tồn kho, gửi email xác nhận. QA viết test, tất cả đều xanh, tính năng lên production.

Một tuần sau, vào đợt sale 6.6, một sản phẩm hot chỉ còn 3 cái trong kho nhưng có 50 người bấm "đặt" gần như cùng lúc. Hệ thống tạo ra 50 đơn hàng — bán âm 47 sản phẩm. Đây là lỗi race condition ở tầng nghiệp vụ tồn kho, và nó không bị bắt vì test chỉ chạy tuần tự từng request một, không mô phỏng nhiều request đồng thời.

Diễn giải: acceptance criteria của BA thiếu một câu cực kỳ quan trọng: "Khi tồn kho không đủ cho các đơn đồng thời, hệ thống phải từ chối đơn vượt quá và trả về 409 Conflict." Đây vừa là functional test (đặt khi hết hàng → 409), vừa cần một concurrency test (50 request song song chỉ 3 đơn thành công).

Bài học rút ra: BA phải tư duy về các trường hợp đồng thời và cạnh tranh tài nguyên, đặc biệt với các nghiệp vụ "đếm số lượng" (tồn kho, vé, suất học). Một dòng acceptance criteria rõ ràng ở đây đáng giá bằng cả buổi điều tra sự cố sau này.

Tình huống 2: Startup fintech và contract testing cứu một bàn thua

Một startup fintech tại TP.HCM cung cấp API cho các đối tác (ví điện tử, ngân hàng số) gọi vào để truy vấn điểm tín dụng. Mỗi response trả về trường credit_score kiểu số nguyên. Một ngày đẹp trời, đội backend "tối ưu" và đổi credit_score từ số nguyên (ví dụ 720) sang chuỗi ("720") cho thống nhất định dạng. Test functional nội bộ vẫn xanh vì giá trị vẫn đúng. Nhưng hệ thống của đối tác — vốn parse trường này thành số để so sánh — lập tức lỗi hàng loạt, treo luồng duyệt vay của họ.

May mắn là đội này đã thiết lập contract test dựa trên file OpenAPI: bộ test tự động phát hiện kiểu dữ liệu của credit_score không còn khớp "hợp đồng" đã ký với đối tác, và chặn bản build trước khi nó lên production. Sự cố được ngăn ngay trong CI.

Diễn giải: đây là sức mạnh của contract testing. Khi nhiều đội/nhiều công ty tích hợp với nhau, bất kỳ thay đổi nhỏ nào về cấu trúc response cũng có thể phá vỡ phía bên kia. Functional test "đúng giá trị" là chưa đủ — phải kiểm cả "đúng hình dạng".

Bài học rút ra: với API public hoặc API liên đội, BA nên ghi vào spec rằng "mọi thay đổi cấu trúc response là breaking change và phải qua quy trình versioning". Đồng thời, BA nên hỏi QA: "Chúng ta đã có contract test gắn với tài liệu OpenAPI chưa?" Câu hỏi đó cho thấy bạn hiểu nghề.

Tình huống 3: Grab và bài học về test trên đúng môi trường

Một đội (bối cảnh kiểu Grab) test tính năng tính phí chuyến đi có áp dụng giá giờ cao điểm (surge). Họ test trên môi trường staging, mọi con số đều khớp, ai cũng yên tâm. Nhưng lên production, công thức surge dùng dữ liệu thời tiết và mật độ giao thông thời gian thực — thứ mà staging không có. Kết quả: trong cơn mưa lớn đầu tiên, hệ số surge nhảy lên mức bất thường vì một biên (cap) chưa được cấu hình đúng trên production, khiến nhiều khách bị tính giá cao vô lý và mạng xã hội dậy sóng.

Diễn giải: test đúng logic nhưng sai môi trường/dữ liệu vẫn có thể bỏ lọt sự cố. Staging không bao giờ giống production 100%. Những thành phần phụ thuộc dữ liệu ngoài (third-party, real-time feed) cần được kiểm tra riêng, lý tưởng là có canary (cho một phần nhỏ traffic thật chạy trước rồi quan sát).

Bài học rút ra: khi BA nghiệm thu (UAT), hãy luôn hỏi: "Test này chạy trên môi trường nào? Dữ liệu có đại diện cho thực tế không? Có biên/cap nào chỉ tồn tại ở production mà chưa được kiểm chưa?" Đây là tư duy chiến lược, không phải tư duy công cụ.

Hướng dẫn từng bước

Dưới đây là quy trình một BA có thể áp dụng để góp phần xây dựng chiến lược test cho một API, từ lúc viết spec đến lúc nghiệm thu.

Bước 1 — Viết acceptance criteria có thể kiểm chứng được. Với mỗi endpoint, viết tiêu chí theo dạng có thể biến thành test. Mẫu hữu ích là Given-When-Then: "Cho rằng (Given) giỏ hàng có 2 sản phẩm còn hàng, Khi (When) gọi POST /orders với token hợp lệ, Thì (Then) nhận 201 và response chứa order_id cùng total_amount đúng." Tránh các câu mơ hồ như "đặt hàng phải hoạt động tốt".

Bước 2 — Liệt kê happy path và sad path song song. Lập một bảng nhỏ: cột trái là kịch bản, cột phải là kết quả mong đợi (status code + nội dung). Bắt buộc có ít nhất 1 happy path và nhiều sad path: thiếu trường bắt buộc → 400, không có token → 401, không đủ quyền → 403, sản phẩm không tồn tại → 404, hết hàng → 409, vượt rate limit → 429.

Bước 3 — Đánh dấu loại test cho từng tiêu chí. Ghi chú bên cạnh mỗi tiêu chí xem nó thuộc functional, contract, performance hay security. Việc này giúp QA biết cần loại test nào và giúp tránh bỏ sót khía cạnh phi chức năng (như "p95 phải dưới 500ms").

Bước 4 — Thống nhất phân tầng với QA theo Test Pyramid. Cùng QA quyết định cái gì test ở tầng API (đa số quy tắc nghiệp vụ) và cái gì thực sự cần E2E (chỉ vài luồng then chốt như "đặt hàng đến khi nhận email"). Mục tiêu là bộ test nhanh, ổn định.

Bước 5 — Xác định dữ liệu và môi trường test. Ghi rõ test chạy ở staging hay sandbox, cần tài khoản/dữ liệu mẫu nào (ví dụ: 1 user còn hạn mức, 1 user hết hạn mức, thẻ test của cổng thanh toán). Thiếu bước này, QA sẽ tốn nhiều thời gian "dựng" dữ liệu.

Bước 6 — Đọc và đánh giá kết quả test. Khi QA gửi báo cáo, BA nên xem độ phủ theo nghiệp vụ, không chỉ con số "coverage %". Hỏi: "Mọi sad path trong spec đã có test tương ứng chưa?" Một bộ test 90% coverage nhưng bỏ sót đúng quy tắc tồn kho thì vẫn nguy hiểm.

Bước 7 — Tham gia UAT có chủ đích. Trong nghiệm thu, đừng chỉ bấm happy path. Chủ động thử vài sad path bằng Postman (đã học ở bài trước) để tự mắt thấy API trả về đúng status code và thông điệp lỗi thân thiện.

Lỗi thường gặp & mẹo

Lỗi 1: Chỉ test happy path. Đây là cái bẫy phổ biến nhất. Mẹo: với mỗi happy path, ép bản thân nghĩ ra tối thiểu ba sad path. Nếu không nghĩ ra, đó là dấu hiệu bạn chưa hiểu đủ nghiệp vụ.

Lỗi 2: Nhầm "test xanh" với "đúng yêu cầu". Test có thể xanh nhưng test sai thứ. Mẹo: BA nên đọc tên các test case, đối chiếu với acceptance criteria của mình. Nếu một tiêu chí không có test nào nhắc tới, nó chưa được kiểm.

Lỗi 3: Dồn mọi thứ lên E2E. Bộ E2E khổng lồ chạy chậm, hay flaky, cuối cùng bị bỏ qua. Mẹo: ưu tiên kiểm quy tắc nghiệp vụ ở tầng API test; chỉ giữ E2E cho vài luồng quan trọng nhất.

Lỗi 4: Bỏ qua contract khi tích hợp liên đội. Mẹo: bất cứ khi nào API được bên thứ ba tiêu thụ, hỏi ngay về contract test gắn với OpenAPI và quy ước versioning.

Lỗi 5: Test sai môi trường/dữ liệu. Mẹo: luôn xác nhận môi trường và độ đại diện của dữ liệu trước khi tin vào kết quả. "Đúng trên staging" không bằng "đúng trên production".

Lỗi 6: Quên test phi chức năng. Nhiều BA chỉ nghĩ tới chức năng mà quên hiệu năng và bảo mật. Mẹo: thêm vào checklist hai câu hỏi cố định — "Ngưỡng thời gian phản hồi là bao nhiêu?" và "Endpoint này có cần phân quyền không?".

Mẹo vàng: giữ một "checklist sad path" cá nhân (thiếu trường, sai kiểu, thiếu auth, sai quyền, không tồn tại, xung đột, quá giới hạn, gọi trùng) và rà nó qua mọi endpoint bạn viết spec. Đây là tài sản nghề nghiệp giúp bạn nổi bật.

Bài tập thực hành

Bài 1 — Lập bảng test cho một endpoint. Cho API POST /vouchers/apply (áp mã giảm giá vào giỏ hàng). Hãy viết một bảng gồm tối thiểu 1 happy path và 6 sad path, mỗi dòng ghi: kịch bản, status code mong đợi, nội dung response mong đợi. Gợi ý các sad path: mã không tồn tại, mã đã hết hạn, mã đã dùng hết lượt, giỏ hàng không đủ giá trị tối thiểu, người dùng chưa đăng nhập, áp hai mã cùng lúc.

Bài 2 — Phân tầng theo Test Pyramid. Cho luồng "người dùng đặt khóa học → thanh toán qua VNPAY → nhận email biên nhận". Hãy quyết định những kiểm tra nào nên đặt ở tầng API test và những kiểm tra nào thực sự cần E2E. Giải thích lý do cho mỗi lựa chọn.

Bài 3 — Săn lỗi contract. Bạn được giao tài liệu OpenAPI ghi rằng response của GET /users/{id} có trường phone kiểu chuỗi và is_verified kiểu boolean. Đội backend vừa đổi is_verified từ true/false sang 1/0. Hãy viết một đoạn ngắn (3-4 câu) giải thích vì sao đây là breaking change, ảnh hưởng tới ai, và bạn sẽ đề xuất xử lý thế nào trong spec.

Bài 4 — Phản biện một báo cáo test. QA báo cáo: "Đã chạy 120 test, tất cả xanh, coverage 88%." Hãy viết ra ba câu hỏi sắc bén mà một BA giỏi sẽ đặt ra trước khi gật đầu nghiệm thu.

Tóm tắt

API testing strategy không phải việc bạn cần biến mình thành QA engineer, mà là tư duy giúp bạn viết spec tốt hơn và nghiệm thu chặt hơn. Hãy ghi nhớ những điểm cốt lõi:

  • Test Pyramid là kim chỉ nam: đa số quy tắc nghiệp vụ nên được kiểm ở tầng API test (nhanh, ổn định), chỉ vài luồng then chốt mới cần E2E (chậm, dễ vỡ).
  • Phân biệt bốn nhánh: functional, contract, performance, security — và biết yêu cầu nào thuộc nhánh nào.
  • Happy path là dễ, sad path mới là nơi BA tạo giá trị. Một acceptance criteria liệt kê đầy đủ sad path đáng giá hơn nhiều buổi điều tra sự cố.
  • Viết tiêu chí theo dạng kiểm chứng được (Given-When-Then, kèm status code và nội dung mong đợi).
  • Luôn xác nhận môi trường và dữ liệu test trước khi tin kết quả — "xanh trên staging" chưa phải là an toàn.
  • Khi đọc báo cáo test, soi độ phủ theo nghiệp vụ, đừng để con số coverage đánh lừa.
Ba tình huống Tiki, fintech TP.HCM và Grab cho thấy cùng một bài học: lỗi đắt giá nhất thường nằm ở những trường hợp mà không ai nghĩ tới test — và người có khả năng nghĩ ra chúng nhất, chính là BA hiểu nghiệp vụ. Hãy biến tư duy kiểm thử thành phản xạ trong mọi spec bạn viết.