Mở đầu — vì sao bài này quan trọng
Cho đến giờ, bạn đã quen chạy Newman qua dòng lệnh: gõ newman run collection.json rồi xem kết quả in ra terminal. Cách này hoạt động tốt khi bạn chỉ cần "bấm nút chạy" một collection. Nhưng thực tế công việc của một API Tester nghiêm túc phức tạp hơn nhiều: bạn muốn chạy collection bên trong một quy trình lớn hơn — sau khi đã gọi API dựng dữ liệu mẫu, đọc kết quả để quyết định có gửi cảnh báo Slack hay không, hay gom kết quả của mười collection lại thành một báo cáo tổng.
Đây chính là lúc bạn cần Newman ở dạng thư viện (library) chứ không phải dạng CLI. Newman thực chất là một package Node.js bình thường, và cái CLI mà bạn quen dùng chỉ là một lớp vỏ mỏng bọc quanh module Node bên trong. Khi bạn require('newman'), bạn có toàn quyền truy cập vào lõi đó: khởi chạy collection bằng code, lắng nghe từng sự kiện trong quá trình chạy, và nhận về một object summary đầy đủ để tự do xử lý.
Sự khác biệt về tư duy ở đây rất quan trọng. Với CLI, Newman là chương trình của bạn. Với library, Newman chỉ là một hàm trong chương trình của bạn — bạn mới là người điều khiển luồng. Bài này tập trung riêng vào kỹ năng nhúng Newman vào code Node.js: cách gọi newman.run(), cách đọc kết quả trả về, cách bắt sự kiện, và cách biến nó thành một mắt xích trong framework test của riêng bạn. (Việc chạy Newman thuần bằng CLI đã nói ở Bài 13, còn cấu hình reporter HTML/JUnit/Allure là chủ đề riêng của Bài 14 — ở đây ta không lặp lại.)
Khái niệm cốt lõi
Newman là một Node module, không chỉ là lệnh terminal
Khi cài npm install newman, bạn nhận được cả hai thứ: một file thực thi (node_modules/.bin/newman) và một module JavaScript có thể require. Module này export ra một object có hàm chính là newman.run(). Toàn bộ sức mạnh của việc "embed" nằm ở hàm này.
Cú pháp cơ bản trông như sau:
const newman = require('newman');newman.run({
collection: require('./collection.json'),
environment: require('./staging.postman_environment.json'),
reporters: ['cli']
}, function (err, summary) {
if (err) { throw err; }
console.log('Collection đã chạy xong!');
});
Object đầu tiên là options — tương đương với các cờ dòng lệnh (--collection, --environment, --iteration-data...). Hàm thứ hai là callback chạy khi collection kết thúc, nhận vào err (lỗi hạ tầng, ví dụ file không đọc được) và summary (kết quả chi tiết của lần chạy).
Ba cách nạp collection và environment
Bạn có thể truyền collection theo nhiều dạng, và chọn đúng dạng giúp code linh hoạt hơn:
- Đường dẫn file:
collection: './collections/api.json'— Newman tự đọc file. - Object đã parse:
collection: require('./api.json')— bạn tự đọc JSON rồi truyền vào. Cách này cho phép bạn sửa collection trong bộ nhớ trước khi chạy (ví dụ chèn thêm biến). - URL:
collection: 'https://api.getpostman.com/collections/{id}?apikey=...'— kéo trực tiếp từ Postman Cloud qua Postman API.
environment và iterationData (file CSV/JSON để chạy data-driven).Object summary — trái tim của việc embed
Đây là điểm khiến library vượt trội hơn CLI. Callback trả về một object summary mô tả toàn bộ lần chạy dưới dạng dữ liệu có cấu trúc. Những nhánh quan trọng nhất:
summary.run.stats— tổng quan số liệu: số request, số assertion, số iteration, và quan trọng nhất là số lượng failed. Ví dụsummary.run.stats.assertions.failed.summary.run.failures— mảng chi tiết từng test thất bại: tên test, thông báo lỗi, request nào gây ra.summary.run.executions— mảng từng request đã chạy, kèm response, thời gian phản hồi, mã trạng thái.summary.run.timings— thời điểm bắt đầu/kết thúc, tổng thời gian chạy.
Lắng nghe sự kiện với .on()
newman.run() trả về một event emitter. Nghĩa là ngoài callback cuối cùng, bạn có thể bắt các sự kiện trong lúc chạy:
newman.run(options)
.on('start', () => console.log('Bắt đầu chạy...'))
.on('request', (err, args) => {
console.log(Gọi: ${args.request.url.toString()} → ${args.response.code});
})
.on('assertion', (err, args) => {
if (err) console.log( ✗ Test thất bại: ${args.assertion});
})
.on('done', (err, summary) => console.log('Hoàn tất.'));
Các sự kiện hữu ích: start, beforeRequest, request, test, assertion, console (bắt output từ console.log trong test script của Postman), và done. Kỹ thuật này cho phép bạn stream tiến trình theo thời gian thực — cực kỳ giá trị khi tích hợp vào dashboard hoặc log tập trung.
Tình huống thực tế
Ví dụ 1 — Tiki: gom 12 collection thành một "orchestrator"
Một đội QA giả định tại một sàn thương mại điện tử kiểu Tiki quản lý 12 collection tách theo domain: auth, cart, checkout, payment, search, inventory... Trước đây họ chạy 12 lệnh Newman CLI riêng lẻ trong một shell script. Vấn đề: khi collection thứ 5 fail, script bash set -e dừng luôn, 7 collection còn lại không chạy, và họ không biết toàn cảnh hệ thống có bao nhiêu lỗi.
Đội chuyển sang viết một file run-all.js dùng Newman library:
const newman = require('newman');
const collections = ['auth', 'cart', 'checkout', 'payment', 'search'];async function runOne(name) {
return new Promise((resolve) => {
newman.run({
collection: require(./collections/${name}.json),
environment: require('./env/staging.json'),
reporters: []
}, (err, summary) => {
resolve({
name,
failed: err ? -1 : summary.run.stats.assertions.failed,
total: err ? 0 : summary.run.stats.assertions.total
});
});
});
}
(async () => {
const results = [];
for (const c of collections) results.push(await runOne(c));
console.table(results);
const totalFailed = results.reduce((s, r) => s + Math.max(r.failed, 0), 0);
process.exit(totalFailed > 0 ? 1 : 0);
})();
Kết quả: mọi collection đều chạy đến hết, đội thấy được một bảng "auth: 0/40, payment: 3/55, search: 1/28" ngay lập tức, và exit code vẫn báo fail cho CI. Bài học: library cho phép bạn kiểm soát luồng — chạy tiếp dù có lỗi, rồi tự quyết định khi nào coi cả suite là thất bại, điều mà chuỗi lệnh CLI rời rạc rất khó làm.
Ví dụ 2 — Startup fintech ở TP.HCM: cổng gác trước khi deploy
Một startup ví điện tử tại TP.HCM chạy khoảng 8 lần deploy staging mỗi ngày. Họ muốn: sau mỗi deploy, chạy bộ smoke test API; nếu tỉ lệ pass dưới 98% thì tự động gửi cảnh báo vào channel #qa-alerts trên Slack kèm danh sách test lỗi. CLI không làm được điều này gọn gàng vì bạn phải parse output text; library thì trả sẵn dữ liệu.
newman.run({ collection: require('./smoke.json'), environment: env },
async (err, summary) => {
if (err) return notifySlack(Newman crash: ${err.message});
const { assertions } = summary.run.stats;
const passRate = (assertions.total - assertions.failed) / assertions.total;
if (passRate < 0.98) {
const lines = summary.run.failures.map(f =>
• ${f.error.test}: ${f.error.message}).join('\n');
await notifySlack(⚠ Smoke pass ${(passRate*100).toFixed(1)}%\n${lines});
}
});
Sau khi triển khai, đội bắt được một lỗi rò rỉ: endpoint /wallet/balance thỉnh thoảng trả về số dư âm sau khi rollback giao dịch — test assertion phát hiện, và Slack báo trong vòng 40 giây sau deploy. Bài học: vì summary.run.failures là dữ liệu có cấu trúc, bạn dễ dàng biến kết quả test thành hành động (thông báo, ghi log, chặn deploy) thay vì chỉ là chữ trên màn hình.
Ví dụ 3 — Agency phần mềm: sửa collection trong bộ nhớ trước khi chạy
Một agency ở Đà Nẵng nhận outsource test API cho nhiều khách hàng. Mỗi khách hàng có cùng bộ collection nhưng khác base_url và một x-tenant-id. Thay vì tạo hàng chục file environment, họ nạp collection dạng object, tiêm biến động rồi chạy:
const base = require('./collection.json');
const tenants = [
{ id: 'acme', url: 'https://acme.api.vn' },
{ id: 'global', url: 'https://global.api.vn' }
];for (const t of tenants) {
newman.run({
collection: base,
envVar: [
{ key: 'base_url', value: t.url },
{ key: 'tenant_id', value: t.id }
],
reporters: ['cli']
}, (err, s) => console.log(${t.id}: ${s.run.stats.assertions.failed} lỗi));
}
Chú ý option envVar — nó cho phép override biến ngay từ code, không cần file. Bài học: khi Newman là library, collection và environment trở thành dữ liệu bạn nắm trong tay, cho phép tham số hóa động theo cách CLI không tiện làm.
Hướng dẫn từng bước
Bước 1 — Khởi tạo project và cài Newman.
Tạo thư mục, chạy npm init -y, rồi npm install newman. Bạn không cần cài global; library nằm trong node_modules của project là đủ.
Bước 2 — Export collection và environment.
Từ Postman, export collection ra collection.json (Collection Format v2.1) và environment ra file .postman_environment.json. Đặt chúng vào thư mục project.
Bước 3 — Viết file runner tối thiểu.
Tạo run.js:
const newman = require('newman');newman.run({
collection: require('./collection.json'),
environment: require('./env.json'),
reporters: ['cli']
}, (err, summary) => {
if (err) throw err;
console.log(Failed: ${summary.run.stats.assertions.failed});
});
Chạy node run.js. Nếu thấy output CLI quen thuộc, bạn đã embed thành công.
Bước 4 — Gói vào Promise để dùng async/await. Callback lồng nhau khó đọc khi chạy nhiều collection. Bọc lại:
function runCollection(opts) {
return new Promise((resolve, reject) => {
newman.run(opts, (err, summary) =>
err ? reject(err) : resolve(summary));
});
}
Giờ bạn có thể const summary = await runCollection({...}).
Bước 5 — Đọc summary và ra quyết định.
Sau khi có summary, kiểm tra summary.run.stats.assertions.failed. Nếu lớn hơn 0, gọi process.exit(1) để báo fail cho CI, hoặc kích hoạt logic riêng (gửi thông báo, ghi file JSON).
Bước 6 — Thêm event listener nếu cần realtime.
Gắn .on('assertion', ...) để in từng test ngay lúc chạy, hoặc .on('console', ...) để bắt log từ script Postman phục vụ debug.
Lỗi thường gặp & mẹo
Quên xử lý exit code. Khi chạy CLI, Newman tự set exit code khác 0 nếu có test fail. Khi dùng library, bạn phải tự làm điều đó. Nếu quên, CI sẽ luôn báo "xanh" dù test đỏ. Luôn kết thúc bằng process.exit(summary.run.failures.length > 0 ? 1 : 0).
Nhầm err với test thất bại. Tham số err trong callback chỉ báo lỗi hạ tầng (không đọc được file, collection sai định dạng). Test API thất bại KHÔNG làm err khác null — chúng nằm trong summary.run.failures. Đây là lỗi khái niệm phổ biến nhất khi mới embed.
require collection lớn nhiều lần. require cache module, nên nếu bạn sửa collection trong bộ nhớ ở lần chạy đầu rồi chạy lần hai, bạn có thể vô tình dùng bản đã bị sửa. Với vòng lặp nhiều tenant, cân nhắc deep-clone (JSON.parse(JSON.stringify(base))) trước mỗi lần chạy.
Chạy song song bằng Promise.all mà không kiểm soát. Bắn 20 collection cùng lúc có thể làm quá tải server staging và gây fail giả (timeout, rate limit). Với môi trường VN thường có hạ tầng khiêm tốn, nên chạy tuần tự bằng vòng for...of await, hoặc giới hạn số luồng song song.
Mẹo — tách reporter ra khỏi logic. Bạn có thể để reporters: [] (không in gì) khi chỉ cần dữ liệu summary, rồi tự dựng báo cáo. Điều này giữ output sạch khi chạy nhiều collection trong một orchestrator.
Mẹo — dùng summary.run.executions để đo hiệu năng thô. Mỗi execution có response.responseTime. Bạn có thể tính p95 thời gian phản hồi ngay trong runner mà không cần công cụ ngoài (dù để đo tải thật thì Postman không thay được k6/JMeter — chủ đề Bài 30).
Bài tập thực hành
- Runner cơ bản. Cài Newman vào một project mới, viết
run.jschạy một collection bất kỳ và in ra tổng số assertion cùng số assertion thất bại từsummary.run.stats.
- Orchestrator nhiều collection. Tạo 3 collection nhỏ. Viết một script chạy cả 3 tuần tự, đảm bảo chạy hết dù collection giữa có test fail, rồi in một bảng tổng kết (dùng
console.table) gồm tên và số lỗi mỗi collection. Cuối cùng set exit code đúng.
- Biến kết quả thành hành động. Mở rộng bài 2: nếu tổng tỉ lệ pass dưới 95%, in ra một danh sách các test thất bại (tên test + message) lấy từ
summary.run.failures. Nếu có tài khoản Slack/Telegram, thử gửi thật danh sách đó qua webhook.
- Tham số hóa động. Dùng một collection duy nhất, chạy nó hai lần cho hai
base_urlkhác nhau bằng optionenvVar, không tạo thêm file environment nào. Xác nhận cả hai lần đều dùng đúng URL bằng cách bắt sự kiện.on('request', ...).
Tóm tắt
Newman không chỉ là một lệnh terminal — nó là một Node module bạn có thể require và nhúng vào bất kỳ framework test nào. Điểm mấu chốt là hàm newman.run(options, callback): options tương ứng các cờ CLI (collection, environment, iterationData, envVar), còn callback trả về object summary chứa toàn bộ kết quả dưới dạng dữ liệu có cấu trúc. Chính object summary — với stats, failures, executions — là thứ mở ra mọi khả năng: gom nhiều collection, biến kết quả test thành thông báo hay cổng gác deploy, tham số hóa động theo tenant, và stream tiến trình qua các sự kiện .on().
Hãy nhớ ba điều dễ sai: err chỉ là lỗi hạ tầng chứ không phải test fail (test fail nằm trong summary.run.failures); bạn phải tự set exit code cho CI; và cẩn thận khi chạy song song hoặc tái dùng collection đã sửa trong bộ nhớ. Khi nắm vững kỹ năng embed này, bạn không còn "chạy Newman" nữa — bạn lập trình Newman thành một mắt xích trong hệ thống kiểm thử của riêng mình.