Product Management
Đăng nhập
ESC

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

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

Project 1: VN E-commerce API Test Suite

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

Bạn đã đi qua 52 bài học: biết viết assertion, chạy Newman, quản lý environment, xử lý OAuth, chain request, kiểm thử schema. Nhưng có một khoảng cách rất lớn giữa "biết từng kỹ thuật rời rạc" và "dựng được một bộ kiểm thử API hoàn chỉnh cho một hệ thống thật". Trong phỏng vấn vị trí API Tester hay SDET tại Tiki, Shopee, Sendo hay các công ty gia công như KMS, FPT Software, người ta không hỏi bạn "pm.test viết thế nào". Họ đưa cho bạn một sơ đồ hệ thống e-commerce năm service và hỏi: "Em sẽ tổ chức bộ test ra sao? Order phụ thuộc Cart, Cart phụ thuộc Auth — em chạy theo thứ tự nào? Làm sao chạy được trên CI mà không phụ thuộc dữ liệu tay?"

Bài này là dự án thực chiến đầu tiên của khóa. Chúng ta không học kỹ thuật mới — chúng ta ghép mọi thứ đã học thành một API test suite hoàn chỉnh cho một sàn thương mại điện tử kiểu Shopee của Việt Nam. Mục tiêu là bạn kết thúc bài với một Collection có cấu trúc rõ ràng, khoảng 80 test case phủ năm service, chạy được bằng một lệnh Newman duy nhất từ máy trắng (fresh machine) mà không cần bấm tay. Đây chính là artifact bạn có thể đưa vào portfolio và demo trong phỏng vấn.

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

Hệ thống dưới thử nghiệm (System Under Test)

Ta mô phỏng một sàn TMĐT tên ShopVN, gồm năm microservice độc lập:

  • Auth (/auth): đăng ký, đăng nhập, refresh token, lấy profile. Trả về JWT.
  • Catalog (/catalog): danh sách sản phẩm, chi tiết, tìm kiếm, tồn kho.
  • Cart (/cart): thêm/xóa/sửa item, xem giỏ, tính tạm tính.
  • Order (/orders): tạo đơn từ giỏ, xem đơn, hủy đơn, theo dõi trạng thái.
  • Payment (/payments): khởi tạo thanh toán, callback trạng thái, hoàn tiền.
Điểm mấu chốt của một hệ thống thật là các service phụ thuộc lẫn nhau theo chuỗi nghiệp vụ: bạn phải có token từ Auth mới gọi được Cart; phải có sản phẩm còn hàng từ Catalog mới thêm được vào Cart; phải có giỏ hàng mới tạo được Order; phải có Order mới khởi tạo được Payment. Đây gọi là dependency graph của test suite, và nó quyết định toàn bộ kiến trúc bộ test.

Kim tự tháp phủ (coverage) cho một bộ API test

Với ~80 test case, ta không rải đều mỗi service 16 test. Ta phân bổ theo rủi ro nghiệp vụ:

  • Happy path (luồng thuận): đủ để chứng minh mỗi endpoint hoạt động — khoảng 40% số test.
  • Validation / negative (đầu vào sai): thiếu field, sai kiểu, vượt giới hạn — khoảng 35%. Đây là nơi bug thật ẩn nấp.
  • Authorization / bảo mật: gọi không token, token hết hạn, user A xem đơn user B (IDOR) — khoảng 15%.
  • Edge nghiệp vụ: thêm sản phẩm hết hàng vào giỏ, thanh toán đơn đã hủy, hoàn tiền hai lần (idempotency) — khoảng 10%.

Ba nguyên tắc kiến trúc bất di bất dịch

1. Độc lập và lặp lại được (idempotent). Chạy suite lần thứ nhất và lần thứ mười phải cho cùng kết quả. Muốn vậy, mỗi lần chạy phải tự tạo dữ liệu của mình — Auth phải đăng ký một user mới với email ngẫu nhiên (user_{{$timestamp}}@shopvn.test) thay vì hard-code test@gmail.com mà lần sau đăng ký lại sẽ báo trùng.

2. Truyền trạng thái qua biến, không qua tay. access_token, product_id, cart_id, order_id sinh ra ở request trước phải được lưu vào environment/collection variable và tiêu thụ ở request sau. Không có chuyện copy-paste ID.

3. Fail phải nói được tại sao. Tên test rõ ràng (Order → tạo đơn trả 201 và có order_id) và assertion tách nhỏ để khi đỏ, người đọc report biết ngay khâu nào hỏng mà không cần mở Postman.

Tình huống thực tế

Tình huống 1 — Bộ test "chạy máy tôi thì xanh, lên CI thì đỏ" ở Tiki

Một bạn QA mới vào một team tại một sàn TMĐT lớn kể lại: bạn tự tin đưa Collection 78 test lên GitHub Actions, và pipeline đỏ ngay dòng đầu. Lý do: request đầu tiên là "Login" với email qa_le@tiki.test mà bạn đã đăng ký thủ công trên máy staging từ tuần trước. Máy CI dùng database staging đã bị reset hằng đêm nên user đó không tồn tại — 401. Cả chuỗi 77 test sau sập theo.

Bài học: bộ test không được giả định bất kỳ dữ liệu tồn tại sẵn nào. Bạn ấy sửa lại: request #0 Register chạy đầu tiên, sinh email động bằng pm.variables.replaceIn('{{$randomEmail}}'), lưu password vào biến, rồi #1 Login dùng chính user vừa tạo. Từ đó pipeline xanh ổn định. Đây là lý do nguyên tắc "self-seeding data" nằm ở dòng đầu tiên của mọi suite nghiêm túc.

Tình huống 2 — 80 test xanh nhưng bug lọt lưới ở Cart

Một team tại Sendo có bộ 80 test đều xanh, nhưng khách hàng phản ánh: thêm sản phẩm số lượng âm (quantity: -5) vào giỏ thì tổng tiền giỏ bị âm, và khi checkout hệ thống... tặng tiền cho khách. Khi rà lại, bộ test chỉ có happy path: thêm quantity: 2, quantity: 1. Không có một test negative nào cho quantity.

Họ bổ sung ngay nhóm test validation cho Cart: quantity = 0, quantity = -5, quantity = 999999 (vượt tồn), quantity = "abc" (sai kiểu), thiếu field product_id. Kết quả: 3/5 test đỏ — server nhận cả số âm và trả 200. Bug được vá trước khi lên production. Bài học đắt giá: số lượng test xanh không đo được chất lượng; phân bổ negative test mới đo được. Đây là lý do ta cố định 35% suite cho validation.

Tình huống 3 — IDOR ở Order suýt lộ đơn hàng khách khác

Trong một đợt kiểm thử tại một startup fintech Đông Nam Á, QA thêm một test đơn giản: đăng ký hai user A và B, user A tạo đơn order_id = 1042, sau đó dùng token của B gọi GET /orders/1042. Kỳ vọng: 403 Forbidden. Thực tế: 200, trả về đầy đủ địa chỉ, số điện thoại, danh sách hàng của A. Đây là lỗi IDOR (Insecure Direct Object Reference) — một trong những lỗ hổng phổ biến nhất của API TMĐT.

Bài học: bộ test cấp production phải có nhóm "authorization edge case" cross-user. Chỉ tốn thêm một request nhưng phát hiện được lỗ hổng có thể khiến công ty vi phạm Nghị định 13/2023 về bảo vệ dữ liệu cá nhân. Đây là 15% authorization trong phân bổ của ta.

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

Bước 1 — Dựng khung Collection. Tạo Collection ShopVN API Suite, bên trong tạo 5 folder theo service: 01 Auth, 02 Catalog, 03 Cart, 04 Order, 05 Payment. Đánh số prefix để Newman chạy đúng thứ tự phụ thuộc (Newman chạy tuần tự theo thứ tự trong collection). Trong mỗi folder, đặt tên request theo mẫu [service] [hành động] — [kỳ vọng].

Bước 2 — Environment. Tạo environment shopvn-staging với biến khởi tạo: base_url = https://staging-api.shopvn.test. Để trống các biến sẽ sinh động: access_token, refresh_token, user_email, user_password, product_id, cart_id, order_id, payment_id. Giữ base_url ở environment để đổi sang production chỉ bằng cách chọn environment khác.

Bước 3 — Seed dữ liệu ở Auth. Request 01 Register:

// Pre-request: sinh danh tính duy nhất cho lần chạy này
const email = qa_${Date.now()}@shopvn.test;
const pass = 'Test@12345';
pm.environment.set('user_email', email);
pm.environment.set('user_password', pass);

Body dùng {{user_email}}, {{user_password}}. Tests:

pm.test('Register trả 201', () => pm.response.to.have.status(201));
pm.test('Có user_id', () => {
  pm.expect(pm.response.json()).to.have.property('user_id');
});

Bước 4 — Login và bắt token. Request 02 Login dùng lại {{user_email}}/{{user_password}}:

pm.test('Login 200', () => pm.response.to.have.status(200));
const body = pm.response.json();
pm.expect(body).to.have.property('access_token');
pm.environment.set('access_token', body.access_token);
pm.environment.set('refresh_token', body.refresh_token);

Đặt header Authorization: Bearer {{access_token}}cấp Collection (Authorization tab) để mọi request con kế thừa, khỏi khai lại từng cái.

Bước 5 — Catalog cho ra product_id thật. Request 03 List Products, sau đó lấy một sản phẩm còn hàng để chuyền xuống Cart:

const items = pm.response.json().data;
const inStock = items.find(p => p.stock > 0);
pm.expect(inStock, 'phải có ít nhất 1 SP còn hàng').to.exist;
pm.environment.set('product_id', inStock.id);

Bước 6 — Chuỗi Cart → Order → Payment. 04 Add to Cart dùng {{product_id}}, lưu cart_id. 05 Create Order dùng {{cart_id}}, lưu order_id. 06 Init Payment dùng {{order_id}}, lưu payment_id. Mỗi request: assert status, assert thân dữ liệu, và set biến cho bước sau. Đây chính là kỹ thuật chained request bạn đã học, giờ áp vào nghiệp vụ thật.

Bước 7 — Rải negative và authorization. Trong mỗi folder thêm nhóm test âm ngay sau happy path: Auth (login sai mật khẩu → 401, email sai định dạng → 422); Cart (quantity âm/0/vượt tồn); Order (tạo đơn từ cart rỗng → 400); Payment (thanh toán order đã hủy → 409). Thêm một request cross-user cho Order để bắt IDOR như tình huống 3.

Bước 8 — Chạy bằng Newman. Từ terminal, một lệnh duy nhất tái tạo toàn bộ:

newman run shopvn.postman_collection.json \
  -e shopvn-staging.postman_environment.json \
  --reporters cli,htmlextra \
  --reporter-htmlextra-export report.html

Vì suite tự seed dữ liệu, lệnh này chạy được trên máy trắng, trên CI, hay của đồng nghiệp — luôn cho kết quả nhất quán.

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

Hard-code ID và token. Lỗi phổ biến nhất của người mới: dán order_id = 1042 copy từ lần chạy tay. Lần sau order đó không tồn tại, test đỏ. Luôn để giá trị chảy qua biến từ request sinh ra nó.

Chạy sai thứ tự. Nếu để Postman chạy alphabet mà không đánh số prefix, Cart có thể chạy trước Auth → chưa có token → sập chuỗi. Đánh số 01/02/... cho cả folder lẫn request, và test lại đúng bằng Newman (Newman tôn trọng thứ tự collection).

Không dọn dữ liệu. Mỗi lần chạy đẻ ra một user và vài đơn rác trên staging. Nếu API có endpoint xóa, thêm request cleanup cuối suite; nếu không, thống nhất với dev một prefix email (qa_...) để cron dọn định kỳ.

Assertion gộp một cục. pm.test('order ok', () => { status; có id; đúng total }) — khi đỏ không biết khâu nào hỏng. Tách thành ba pm.test riêng để report chỉ đường.

Mẹo — dùng biến {{$timestamp}}/{{$randomEmail}} để bảo đảm tính duy nhất. Mẹo — bật --bail trên CI để dừng ngay khi khâu seed hỏng, tránh 60 test đỏ dây chuyền che mất nguyên nhân gốc. Mẹo — tách access_token của user phụ (biến access_token_b) để phục vụ test cross-user mà không đè token chính.

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

  • Dựng Collection ShopVN API Suite với 5 folder đánh số và environment shopvn-staging như hướng dẫn (bạn có thể trỏ vào một mock server tự tạo hoặc một public API giả lập TMĐT).
  • Hoàn thiện chuỗi happy path Register → Login → List Products → Add to Cart → Create Order → Init Payment, truyền toàn bộ trạng thái qua biến, không hard-code một ID nào.
  • Bổ sung đủ ~80 test theo phân bổ: 40% happy, 35% negative, 15% authorization (gồm ít nhất một test IDOR cross-user), 10% edge nghiệp vụ.
  • Chạy toàn bộ bằng một lệnh Newman với reporter htmlextra, xuất report.html. Xóa environment values đã set, chạy lại lần hai — xác nhận vẫn xanh (chứng minh tính idempotent).
  • Cố ý làm hỏng một khâu (đổi base_url sai) và quan sát report có chỉ đúng request đầu tiên đỏ hay không — đây là bài kiểm tra chất lượng đặt tên test của bạn.

Tóm tắt

Bài này biến kiến thức rời rạc thành một API test suite hoàn chỉnh cho hệ thống TMĐT năm service: Auth, Catalog, Cart, Order, Payment. Ba trụ cột kiến trúc cần khắc cốt: (1) suite phải tự seed dữ liệu để chạy được trên máy trắng và trên CI; (2) trạng thái chảy qua biến, không qua tay; (3) test fail phải nói được tại sao nhờ đặt tên rõ và tách assertion. Phân bổ ~80 test theo rủi ro — 40% happy, 35% negative, 15% authorization, 10% edge — mới là thước đo chất lượng thật, không phải số test xanh. Ba tình huống ở Tiki, Sendo và startup fintech cho thấy: bỏ qua self-seeding thì đỏ trên CI, bỏ qua negative thì lọt bug tính tiền, bỏ qua authorization thì lộ dữ liệu khách. Artifact bạn tạo ra ở đây — Collection + environment chạy bằng một lệnh Newman — chính là thứ đưa vào portfolio và demo được trong phỏng vấn API Tester. Các dự án tiếp theo (Payment gateway, GraphQL, Performance smoke) sẽ dựng trên đúng khung tư duy này.

Học xong bài này rồi? Tạo tài khoản miễn phí để lưu lại — lần sau vào là biết ngay đang dở ở đâu, và học hết khóa thì có chứng chỉ. Lưu tiến độ của tôi