Menu
ESC

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

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

Đang tải...

Capstone — End-to-End API Suite

API Testing with Postman Advanced Bài 59/60

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

Suốt 58 bài trước, bạn đã học từng mảnh ghép: collection có cấu trúc, biến và scope, pre-request script, test script, JSON schema validation, chained requests, OAuth 2.0, Newman, reporters, data-driven testing, CI/CD, mock server, Postman Vault, contract testing... Mỗi thứ bạn đều đã chạm tới, nhưng có một sự thật phũ phàng: biết từng viên gạch không có nghĩa là xây được cả ngôi nhà.

Trong thực tế đi làm, không ai giao cho bạn một request lẻ để test. Người ta giao cho bạn một hệ thống — nhiều service, nhiều môi trường, nhiều luồng nghiệp vụ đan xen, và một câu hỏi duy nhất: "Anh/chị đảm bảo được API này chạy đúng chứ?". Capstone chính là bài học dạy bạn cách trả lời câu hỏi đó một cách chuyên nghiệp, có bằng chứng, và tự động hoá được.

Bài này khác mọi bài trước ở chỗ nó không dạy thêm tính năng mới. Nó dạy bạn tư duy tích hợp — cách sắp xếp tất cả những gì đã học thành một API Test Suite hoàn chỉnh, đủ tốt để đưa vào CV, đủ tốt để chạy trong pipeline production, và đủ tốt để một QA lead nhìn vào là gật đầu. Chúng ta sẽ cùng xây một dự án showcase duy nhất: Booking Hotel API kiểu TripAdvisor/Agoda, gồm 6 microservice. Đây sẽ là tấm bằng thực hành lớn nhất của cả khoá.

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

Capstone là gì và nó chứng minh điều gì

Capstone (đồ án tốt nghiệp) không phải là "làm cho nhiều". Nó là bằng chứng cho thấy bạn có thể tự chủ toàn bộ vòng đời testing một hệ thống thật: từ đọc tài liệu API, thiết kế test suite, viết assertion, dựng data-driven, chạy qua CI/CD, đến xuất báo cáo cho stakeholder. Một nhà tuyển dụng SDET ở Việt Nam khi phỏng vấn thường không hỏi "pm.test là gì" — họ mở GitHub của bạn và xem bạn tổ chức một suite thật như thế nào.

Bối cảnh dự án: Booking Hotel API với 6 service

Hãy hình dung bạn là QA của một startup du lịch tên VietStay (giả định), sản phẩm tương tự Agoda thu nhỏ. Backend là kiến trúc microservice gồm:

  • User Service — đăng ký, đăng nhập, quản lý hồ sơ, phát JWT.
  • Hotel Service — quản lý danh mục khách sạn, phòng, giá.
  • Search Service — tìm kiếm khách sạn theo thành phố/ngày/khách, phân trang, lọc, sắp xếp.
  • Booking Service — tạo đơn đặt phòng, giữ chỗ, huỷ.
  • Payment Service — thanh toán (giả lập VNPay sandbox), idempotency.
  • Review Service — đánh giá khách sạn sau khi ở.
Sáu service này phụ thuộc lẫn nhau. Bạn không thể tạo booking nếu chưa đăng nhập; không thể review nếu chưa có booking đã hoàn tất. Chính sự phụ thuộc đó tạo nên một workflow đầu-cuối (end-to-end) mà một test suite tốt phải mô phỏng được.

Ba lớp test trong một suite trưởng thành

Một suite capstone chuyên nghiệp không chỉ có "happy path". Nó phải phân tầng rõ ràng:

  • Smoke tests — kiểm tra nhanh các endpoint quan trọng còn sống (health check, login, search). Chạy trong vài giây, dùng để gác cổng deploy.
  • Functional / E2E tests — mô phỏng hành trình người dùng thật: đăng ký → tìm → đặt → thanh toán → đánh giá. Đây là trái tim của capstone.
  • Negative & edge tests — đặt phòng đã hết, thanh toán trùng, token hết hạn, phân trang vượt giới hạn, ký tự Unicode tiếng Việt trong tên khách sạn.
Suite của bạn cần cả ba tầng, được tổ chức bằng folder trong collection để chạy chọn lọc (--folder trong Newman).

Kiến trúc thư mục và dữ liệu

Một capstone đáng tin cậy cần tách bạch: collection (logic test), environment (dev/staging), data file (CSV/JSON cho data-driven), reporter config, và pipeline file. Cấu trúc gợi ý:

vietstay-api-suite/
├── collections/vietstay.postman_collection.json
├── environments/dev.postman_environment.json
├── environments/staging.postman_environment.json
├── data/hotels-search.csv
├── data/booking-scenarios.json
├── reports/            (Newman xuất ra đây)
├── .github/workflows/api-tests.yml
└── README.md

Tình huống thực tế

Tình huống 1 — VietStay và cái bẫy "chạy máy tôi thì được"

Nhóm QA của VietStay có 4 người. Mỗi người viết collection riêng, lưu biến token cứng trong request. Khi demo cho CTO, mọi thứ xanh lè. Nhưng khi đưa lên pipeline staging, 60% test đỏ. Lý do: token hard-code đã hết hạn, base URL trỏ về localhost, và không ai chain login trước khi gọi booking.

Bài học rút ra: một capstone thật phải không phụ thuộc trạng thái máy cá nhân. Mọi biến động (token, ID booking, ngày check-in) đều phải sinh động ở runtime qua pre-request script và lưu vào biến environment/collection, không được hard-code. Con số biết nói: sau khi refactor để login-đầu-luồng và dùng pm.environment.set('token', ...), tỷ lệ test đỏ giả (flaky) của VietStay giảm từ 60% xuống dưới 3%.

Tình huống 2 — Đơn đặt phòng bị nhân đôi ở Payment Service

Một QA junior tên Minh chỉ test happy path: đặt phòng 1 lần, thanh toán 1 lần, xanh. Production ra mắt, khách hàng bấm nút "Thanh toán" hai lần do mạng chậm, và bị trừ tiền hai lần cho cùng một booking. Sự cố lên tới 47 giao dịch trùng trong tuần đầu, thiệt hại uy tín nghiêm trọng.

Trong capstone, Minh thêm một test edge: gửi cùng một request thanh toán với cùng Idempotency-Key hai lần liên tiếp bằng pm.sendRequest, rồi assert lần thứ hai trả về cùng transaction ID chứ không tạo giao dịch mới.

// Test script trong Payment folder
const firstTxn = pm.collectionVariables.get("firstTxnId");
const body = pm.response.json();
pm.test("Idempotency: gọi lần 2 KHÔNG tạo giao dịch mới", function () {
    pm.expect(body.transactionId).to.eql(firstTxn);
    pm.expect(pm.response.code).to.be.oneOf([200, 409]);
});

Bài học: capstone không chỉ chứng minh "hệ thống chạy" mà còn chứng minh "hệ thống chịu được cách người dùng thật hành xử". Đây chính là thứ phân biệt một API Tester với một SDET.

Tình huống 3 — Báo cáo mà sếp không cần biết code

Chị Lan, QA Lead tại một công ty fintech ở TP.HCM, kể rằng ứng viên gây ấn tượng nhất với chị không phải người viết nhiều test nhất, mà là người khi được hỏi "kết quả thế nào" đã mở ra một báo cáo Newman HTML sạch đẹp, có phần trăm pass/fail theo từng service, thời gian phản hồi trung bình, và link CI xanh. Ứng viên đó chạy newman run ... -r htmlextra,junit và gắn artifact vào GitHub Actions.

Bài học: một capstone không có báo cáo giống như một chuyến bay không có hộp đen. Người ra quyết định không đọc console.log của bạn — họ đọc báo cáo. Suite của bạn phải xuất được HTML (cho người) và JUnit (cho pipeline) ngay từ đầu.

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

Dưới đây là lộ trình xây VietStay API Suite từ con số 0 đến khi chạy tự động trong CI/CD.

Bước 1 — Thiết kế collection theo folder. Tạo collection VietStay E2E Suite. Bên trong chia 3 folder cấp cao: 01_Smoke, 02_E2E_Journey, 03_Negative_Edge. Trong 02_E2E_Journey tạo các sub-folder theo đúng thứ tự nghiệp vụ: AuthSearchBookingPaymentReview. Thứ tự folder chính là thứ tự Newman chạy, nên nó phản ánh workflow thật.

Bước 2 — Dựng environment. Tạo devstaging với các biến: baseUrl, userEmail, userPassword. Tuyệt đối không để token, bookingId, hotelId trong environment tĩnh — những giá trị này sẽ được sinh ở runtime. Với secret thật (API key Payment), dùng Postman Vault thay vì lưu trong environment.

Bước 3 — Auth và chaining. Trong folder Auth, request Login lưu token:

// Tests của request Login
const res = pm.response.json();
pm.test("Login trả về JWT hợp lệ", function () {
    pm.expect(pm.response.code).to.eql(200);
    pm.expect(res.accessToken).to.be.a("string").and.not.empty;
});
pm.collectionVariables.set("token", res.accessToken);

Các request sau dùng header Authorization: Bearer {{token}}. Đây là chained request — nền tảng của E2E.

Bước 4 — Data-driven cho Search. Chuẩn bị hotels-search.csv với các dòng: thành phố (Đà Nẵng, Hội An, Phú Quốc), ngày, số khách, kết quả kỳ vọng tối thiểu. Newman sẽ lặp qua từng dòng. Nhớ test cả Unicode tiếng Việt: assert response chứa "Khách sạn Mường Thanh" đúng dấu, không bị lỗi encoding.

Bước 5 — Booking với dữ liệu động. Lấy hotelId từ kết quả Search (lưu vào biến), tạo booking, lưu bookingId. Assert cả status code lẫn schema bằng JSON Schema validation (bạn đã học ở Bài 10):

const schema = {
    type: "object",
    required: ["bookingId", "status", "totalPrice"],
    properties: {
        bookingId: { type: "string" },
        status: { type: "string", enum: ["PENDING", "CONFIRMED"] },
        totalPrice: { type: "number", minimum: 0 }
    }
};
pm.test("Booking đúng schema", () => {
    pm.expect(pm.response.json()).to.have.jsonSchema(schema);
});

Bước 6 — Payment và edge idempotency. Sinh Idempotency-Key bằng pm.variables.replaceIn('{{$guid}}'), gửi thanh toán, lưu transactionId. Trong folder Negative, gửi lại đúng key đó và assert không nhân đôi (như tình huống 2).

Bước 7 — Review khép vòng. Chỉ cho review khi booking COMPLETED. Test cả case hợp lệ lẫn case cố review khi chưa ở (phải trả 403).

Bước 8 — Chạy bằng Newman và xuất báo cáo.

newman run collections/vietstay.postman_collection.json \
  -e environments/staging.postman_environment.json \
  -d data/hotels-search.csv \
  -r cli,htmlextra,junit \
  --reporter-htmlextra-export reports/report.html \
  --reporter-junit-export reports/junit.xml

Bước 9 — Gắn vào CI/CD. Trong .github/workflows/api-tests.yml, cài Newman, chạy lệnh trên, upload reports/ làm artifact. Đặt smoke folder chạy trước làm gác cổng: nếu smoke đỏ thì dừng, không chạy tiếp E2E để tiết kiệm thời gian.

Bước 10 — Viết README. Mô tả kiến trúc, cách chạy local, cách đọc báo cáo, độ phủ. Đây là thứ nhà tuyển dụng đọc đầu tiên.

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

  • Hard-code token/ID. Lỗi phổ biến nhất. Mọi giá trị động phải sinh ở runtime và lưu vào biến. Nếu bạn thấy một chuỗi eyJhbGci... trong request, đó là một quả bom hẹn giờ.
  • Không kiểm soát thứ tự chạy. Newman chạy tuần tự theo thứ tự folder/request. Nếu Payment đứng trước Booking, cả suite sập. Sắp xếp folder đúng thứ tự nghiệp vụ.
  • Chỉ test happy path. Suite không có folder Negative là suite chưa trưởng thành. Ít nhất phải có: token hết hạn, tài nguyên không tồn tại (404), thiếu quyền (403), dữ liệu sai định dạng (400), idempotency.
  • Assert quá lỏng. pm.response.to.have.status(200) là chưa đủ. Phải assert cả body, schema, và giá trị nghiệp vụ (giá tiền, trạng thái).
  • Bỏ quên Unicode tiếng Việt. Rất nhiều suite VN chết vì tên "Đà Nẵng" bị so sánh với "Ä?à Ná?µng". Luôn có ít nhất một test kiểm tra encoding UTF-8.
  • Mẹo — dùng biến collection cho state, environment cho config. State động (token, bookingId) để ở collection variable; cấu hình môi trường (baseUrl) để ở environment. Tách bạch giúp chuyển dev/staging không vỡ.
  • Mẹo — chạy --bail khi debug, bỏ khi CI. Khi phát triển, --bail dừng ngay lỗi đầu. Trong CI, bỏ --bail để thấy toàn cảnh mọi lỗi trong một lần chạy.

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

  • Dựng khung suite. Tạo collection VietStay với đúng 3 folder cấp cao và các sub-folder E2E theo thứ tự Auth → Search → Booking → Payment → Review. Tạo 2 environment devstaging.
  • Chain đầu-cuối. Viết luồng: Login (lưu token) → Search Đà Nẵng (lưu hotelId) → Booking (lưu bookingId) → Payment (lưu transactionId) → Review. Mỗi bước phải dùng biến từ bước trước, không hard-code.
  • Data-driven. Tạo hotels-search.csv với tối thiểu 4 dòng (gồm 1 dòng tên khách sạn có dấu tiếng Việt) và chạy Search lặp qua dữ liệu bằng Newman.
  • Negative & edge. Viết ít nhất 4 test âm: token hết hạn (401), hotel không tồn tại (404), review khi chưa ở (403), và idempotency thanh toán (gửi trùng key, assert không nhân đôi).
  • Báo cáo & CI. Chạy Newman xuất htmlextra + junit, rồi tạo workflow GitHub Actions chạy smoke trước, E2E sau, upload báo cáo làm artifact. Chụp màn hình pipeline xanh đưa vào README.
  • Thử thách nâng cao. Thêm một bài đo hiệu năng nhẹ: assert mọi response Search dưới 800ms bằng pm.expect(pm.response.responseTime).to.be.below(800), và giải thích trong README vì sao Postman chỉ dùng cho performance smoke chứ không thay JMeter/k6.

Tóm tắt

Capstone không dạy bạn kỹ thuật mới — nó dạy bạn kết nối tất cả thành một sản phẩm hoàn chỉnh. Qua dự án VietStay Booking Hotel API với 6 service, bạn đã thực hành: thiết kế collection phân tầng (smoke / E2E / negative), quản lý biến và scope đúng cách, chain request qua cả một hành trình người dùng, data-driven testing với Unicode tiếng Việt, JSON schema validation, xử lý edge case như idempotency, chạy bằng Newman và xuất báo cáo HTML/JUnit, rồi tự động hoá trong CI/CD.

Ba nguyên tắc vàng cần khắc cốt: (1) không hard-code trạng thái — mọi thứ động sinh ở runtime; (2) test cả cách người dùng thật hành xử, không chỉ happy path; (3) luôn có báo cáo cho người ra quyết định. Một capstone đạt cả ba tiêu chí này chính là dự án bạn có thể tự tin đặt lên đầu CV, và là bước đệm vững chắc cho hành trình từ API Tester lên SDET ở bài kế tiếp.