Mở đầu — vì sao bài này quan trọng
Hãy tưởng tượng bạn là QA của một startup fintech ở TP.HCM. Mỗi lần developer merge code mới, bạn phải mở Postman lên, chạy tay collection 120 request, mắt căng ra nhìn từng dấu tick xanh đỏ. Một lần bạn nghỉ phép, chẳng ai chạy hộ, và thế là một bug làm sai số dư ví lọt lên production đúng ngày lễ. Khách hàng phàn nàn ầm ĩ, đội trực phải xử lý sự cố lúc 11 giờ đêm.
Câu chuyện này lặp lại ở rất nhiều team Việt Nam, và nó có một điểm chung: bộ test API chỉ chạy khi con người nhớ ra để chạy. Đó chính là lý do bài học hôm nay tồn tại. Chúng ta sẽ biến bộ collection Postman của bạn thành một "người gác cổng tự động", chạy mỗi khi có commit hay pull request, ngay bên trong GitHub — nơi code của bạn đang sống. Đây là mảnh ghép biến API testing từ hoạt động thủ công thành một phần của quy trình phát triển liên tục (CI/CD).
Ở các bài trước bạn đã học Newman — công cụ chạy Postman collection trên command line. Bài này ta không dạy lại Newman từ đầu, mà tập trung riêng vào việc ghép Newman vào GitHub Actions để test chạy tự động trong pipeline. Nếu bạn dùng GitLab hay Jenkins, đó là chủ đề của bài kế tiếp; ở đây ta chỉ nói về GitHub Actions.
Khái niệm cốt lõi
CI/CD và vị trí của API test trong pipeline
CI (Continuous Integration) là thói quen tích hợp code liên tục, mỗi lần tích hợp đều được kiểm tra tự động. CD (Continuous Delivery/Deployment) đưa code đã kiểm tra ra môi trường thật một cách tự động. API test của bạn nằm ở tầng "kiểm tra": sau khi code build xong, trước khi (hoặc ngay sau khi) deploy, ta gọi thật vào API để xác nhận nó vẫn hoạt động đúng như kỳ vọng. Nếu test đỏ, pipeline dừng lại, code không được merge hay deploy. Đây gọi là "quality gate" — cổng chất lượng.
GitHub Actions là gì
GitHub Actions là hệ thống CI/CD tích hợp sẵn trong GitHub. Bạn khai báo một workflow — một file YAML đặt trong thư mục .github/workflows/ của repo. Mỗi workflow gồm:
- Trigger (
on): sự kiện kích hoạt, ví dụpush,pull_request, hay theo lịch (schedule). - Jobs: các nhóm công việc, mỗi job chạy trên một máy ảo (gọi là runner, thường là
ubuntu-latest). - Steps: các bước tuần tự trong một job, mỗi bước là một lệnh shell hoặc một action có sẵn.
Cách Newman sống trong runner
Runner của GitHub Actions là một máy Linux trống. Để chạy Newman, bạn cần: cài Node.js, cài newman (và reporter nếu cần), rồi gọi newman run với file collection và environment. Toàn bộ những thứ này diễn ra trong vài chục giây. Collection và environment bạn có thể export ra file JSON và commit vào repo, hoặc kéo về từ Postman Cloud bằng API key — ta sẽ nói cả hai cách.
Exit code — linh hồn của quality gate
Điểm mấu chốt khiến pipeline biết "đậu hay rớt" là exit code. Khi mọi assertion pass, Newman trả về exit code 0; khi có bất kỳ test nào fail, nó trả về khác 0. GitHub Actions đọc exit code này: khác 0 nghĩa là step thất bại, job đỏ, và nếu bạn cấu hình đúng, pull request sẽ bị chặn merge. Bạn không phải viết thêm dòng logic nào — cơ chế Unix cổ điển này làm hết.
Tình huống thực tế
Ví dụ 1 — Startup giao đồ ăn chặn regression trước khi merge
Một startup giao đồ ăn ở Hà Nội, đội backend 8 người, mỗi ngày mở trung bình 15 pull request. Trước đây họ review code bằng mắt và thỉnh thoảng bug logic tính phí ship lọt qua. QA lead quyết định export collection "Order & Delivery API" (68 request, 210 assertion) ra JSON, commit vào repo, rồi viết một workflow chạy trên mọi pull_request nhắm vào nhánh develop.
Kết quả sau một tháng: 9 pull request bị pipeline chặn vì test đỏ — trong đó có 2 lỗi tính sai phí ship khi đơn hàng vượt 500.000đ (ngưỡng freeship). Những bug này lẽ ra đã lên staging và tốn công QA test tay để phát hiện. Bài học: khi test chạy tự động ngay tại pull request, developer nhận phản hồi trong vòng 90 giây, sửa ngay khi ngữ cảnh còn nóng, thay vì để QA phát hiện muộn hai ngày sau.
Ví dụ 2 — Công ty SaaS chạy smoke test sau mỗi lần deploy
Một công ty SaaS quản lý kho vận ở Đà Nẵng deploy lên production nhiều lần mỗi ngày. Họ tách bộ test thành hai collection: một collection "regression" đầy đủ chạy ở pull request, và một collection "smoke" chỉ 12 request quan trọng nhất (login, tạo đơn, tra cứu tồn kho) chạy sau khi deploy nhắm thẳng vào URL production.
Có lần một thay đổi biến môi trường (env var) khiến service không kết nối được database. Build xanh, deploy xanh, nhưng smoke test đỏ ngay lập tức vì endpoint login trả 500. GitHub Actions gửi thông báo về kênh Slack của team trong vòng 2 phút, đội trực rollback trước khi khách hàng kịp nhận ra. Bài học: test ở pull request bảo vệ bạn khỏi lỗi logic, còn smoke test sau deploy bảo vệ bạn khỏi lỗi cấu hình môi trường thật — hai lớp khác nhau, cần cả hai.
Ví dụ 3 — Sự cố secret lộ trên log
Một bạn QA mới vào nghề ở một agency phần mềm tại Cần Thơ hí hửng dựng pipeline đầu tiên. Bạn ấy nhét thẳng token API và mật khẩu tài khoản test vào file environment JSON rồi commit lên GitHub. Repo là private nên bạn ấy nghĩ không sao. Ba tuần sau công ty mở repo thành public để làm portfolio, và toàn bộ token nằm phơi trong lịch sử Git.
Cách đúng: những giá trị nhạy cảm (token, mật khẩu, base URL nội bộ) phải để trong GitHub Secrets — vào Settings > Secrets and variables > Actions của repo, thêm secret, rồi truyền vào Newman qua biến môi trường hoặc cờ --env-var. Trong log, GitHub tự động che (mask) giá trị secret thành . Bài học:* đừng bao giờ commit secret vào file collection/environment. Git nhớ mọi thứ, kể cả những gì bạn đã xóa.
Hướng dẫn từng bước
Ta sẽ dựng một pipeline hoàn chỉnh chạy Newman trên GitHub Actions.
Bước 1 — Export collection và environment. Trong Postman, chọn collection cần chạy, bấm ba chấm > Export, chọn định dạng Collection v2.1, lưu thành collections/api-regression.json. Làm tương tự với environment (nhưng xóa hết giá trị nhạy cảm trước khi export). Commit các file này vào repo.
Bước 2 — Đưa secret vào GitHub. Vào repo trên GitHub > Settings > Secrets and variables > Actions > New repository secret. Thêm ví dụ API_BASE_URL, API_TOKEN. Đây là nơi lưu các giá trị mà bạn đã cố ý bỏ trống ở file environment.
Bước 3 — Tạo workflow. Tạo file .github/workflows/api-test.yml:
name: API Regressionon:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
jobs:
newman:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install Newman
run: npm install -g newman
- name: Run API tests
run: |
newman run collections/api-regression.json \
--environment environments/staging.json \
--env-var "base_url=${{ secrets.API_BASE_URL }}" \
--env-var "token=${{ secrets.API_TOKEN }}" \
--reporters cli
Bước 4 — Hiểu từng phần. on khai báo pipeline chạy khi push hoặc mở pull request vào main/develop. Job newman chạy trên Ubuntu. Bốn step: lấy code về, cài Node 20, cài Newman, rồi chạy test. Cờ --env-var ghi đè giá trị nhạy cảm bằng secret, nên file JSON trong repo luôn "sạch".
Bước 5 — Đẩy lên và quan sát. Commit, push, mở tab Actions trên GitHub. Bạn sẽ thấy workflow chạy realtime, log Newman hiện ra từng request. Nếu tất cả xanh, job xanh. Thử cố tình sửa một assertion cho fail, push lại, và xem job chuyển đỏ.
Bước 6 — Bật quality gate cho pull request. Vào Settings > Branches > Add branch protection rule cho main, tick "Require status checks to pass before merging" và chọn job newman. Từ giờ, không pull request nào được merge vào main nếu API test còn đỏ.
Bước 7 (tùy chọn) — Kéo collection từ Postman Cloud. Nếu không muốn commit file JSON, bạn có thể lưu Postman API Key vào secret rồi tải collection về lúc chạy:
- name: Run tests from Postman Cloud
run: |
newman run "https://api.getpostman.com/collections/COLLECTION_UID?apikey=${{ secrets.POSTMAN_API_KEY }}"
Cách này giúp test luôn dùng phiên bản collection mới nhất trên Postman, nhưng đánh đổi bằng việc phụ thuộc vào Postman Cloud khi pipeline chạy.
Lỗi thường gặp & mẹo
Quên rằng runner chạy trên internet công cộng. Nếu API staging của bạn nằm sau VPN hay chỉ mở cho IP nội bộ công ty, runner của GitHub không gọi vào được và test sẽ timeout. Giải pháp: dùng self-hosted runner đặt trong mạng nội bộ, hoặc mở một endpoint staging riêng cho CI, hoặc dùng đường hầm (tunnel) có kiểm soát.
Không cache dependency nên pipeline chậm. Mỗi lần cài Newman lại từ đầu tốn 15–30 giây. Với actions/setup-node@v4, bật cache: 'npm' (khi có package.json) để tái sử dụng thư viện. Bộ test nhỏ thì không đáng lo, nhưng khi có nhiều reporter và plugin thì cache giúp giảm đáng kể thời gian.
Pipeline luôn xanh dù test đỏ. Nguyên nhân phổ biến: bạn thêm || true vào cuối lệnh Newman, hoặc dùng reporter theo cách nuốt mất exit code. Đừng làm thế — chính exit code khác 0 mới là thứ chặn merge. Nếu muốn pipeline không dừng ngay để còn upload báo cáo, dùng continue-on-error: true ở step test rồi kiểm tra kết quả ở step sau, chứ đừng che exit code.
Path sai. File collection phải đúng đường dẫn tính từ gốc repo. newman run collections/api.json khác với ./api.json. Nếu báo "file not found", chạy ls -R tạm trong một step để soi cấu trúc thư mục trên runner.
Mẹo — dùng ma trận để test nhiều môi trường. Với strategy.matrix, bạn có thể chạy cùng collection trên cả dev và staging song song, mỗi môi trường một job. Rất tiện khi muốn xác nhận API nhất quán giữa các tầng.
Mẹo — đặt timeout hợp lý. Thêm timeout-minutes: 10 cho job để một request treo không làm pipeline chạy vô tận và đốt phút miễn phí của bạn.
Bài tập thực hành
- Tạo một repo GitHub mới (public để dùng runner miễn phí thoải mái). Export một collection Postman đơn giản gọi vào một API công khai như
https://reqres.inhoặchttps://jsonplaceholder.typicode.com, kèm 3–4 assertion. Commit collection vào repo.
- Viết file
.github/workflows/api-test.ymlchạy Newman trên mọipush. Push lên và xác nhận job xanh trong tab Actions.
- Cố tình sửa một assertion cho sai (ví dụ kỳ vọng status 999). Push lại và quan sát job chuyển đỏ. Đọc kỹ log Newman xem nó chỉ ra assertion nào fail.
- Tạo một GitHub Secret tên
BASE_URL, sửa collection dùng biến{{base_url}}, rồi truyền secret vào Newman qua--env-var. Xác nhận trong log giá trị đã bị che thành*.
- Thêm branch protection rule yêu cầu job Newman phải xanh mới được merge. Mở một pull request có test đỏ và tự kiểm chứng rằng nút Merge bị khóa.
- (Nâng cao) Thêm trigger
schedulechạy collection mỗi sáng 8 giờ (theo giờ UTC, nhớ trừ 7 tiếng cho giờ Việt Nam) để có một bản smoke test định kỳ độc lập với commit.
Tóm tắt
Bài này biến bộ Postman collection của bạn thành một quality gate tự động sống trong GitHub. Những điểm cần khắc cốt ghi tâm:
- GitHub Actions dùng file YAML trong
.github/workflows/, gồm trigger (on), jobs và steps chạy trên runner Ubuntu miễn phí. - Newman chạy trong runner qua bốn bước quen thuộc: checkout, cài Node, cài Newman, chạy test.
- Exit code là linh hồn của quality gate: Newman trả khác 0 khi có test fail, GitHub tự động chuyển job sang đỏ và chặn merge — bạn không cần viết thêm logic.
- Chạy test ở
pull_requestchặn lỗi logic sớm; chạy smoke test sau deploy chặn lỗi cấu hình môi trường thật. Hai lớp bổ trợ nhau. - Mọi giá trị nhạy cảm phải nằm trong GitHub Secrets, không bao giờ commit vào file collection/environment — vì Git nhớ tất cả.