Product Management
Đăng nhập
ESC

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

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

Advanced Assertions và Mock Servers

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

Ở bài trước bạn đã làm quen với những tính năng nâng cao của Postman. Bây giờ chúng ta bước vào hai kỹ năng tạo nên sự khác biệt giữa một người "bấm Send xem status 200" và một QA engineer thực thụ: advanced assertions (kiểm tra sâu response) và mock servers (dựng API giả để test khi backend chưa sẵn sàng).

Vì sao hai chủ đề này lại đi cùng nhau trong một bài? Vì chúng giải quyết hai nỗi đau kinh điển của đội QA. Nỗi đau thứ nhất: bạn viết test chỉ kiểm tra status === 200, rồi backend đổi kiểu dữ liệu price từ số sang chuỗi, đổi tên field userId thành user_id, và test của bạn vẫn xanh lè — bug lọt lên production. Nỗi đau thứ hai: sprint đang chạy, frontend cần API để tích hợp nhưng backend còn 2 tuần nữa mới xong, cả đội ngồi chờ nhau.

Advanced assertions giúp bạn "khóa chặt" hợp đồng dữ liệu (data contract) để mọi thay đổi ngoài ý muốn đều bị phát hiện ngay. Mock servers giúp bạn không bao giờ phải ngồi chờ. Nắm vững hai thứ này, bạn không chỉ test tốt hơn mà còn trở thành người mở khóa tiến độ cho cả team.

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

Assertion là gì và vì sao "assertion nông" nguy hiểm

Trong Postman, một assertion là một câu khẳng định về response mà bạn kiểm chứng bằng pm.test() kết hợp thư viện pm.expect() (dựa trên Chai.js). Một assertion "nông" (shallow) chỉ kiểm tra bề mặt:

pm.test("Status is 200", function () {
    pm.response.to.have.status(200);
});

Assertion này đúng, nhưng nó không bảo vệ bạn khỏi 90% lỗi thực tế. API có thể trả về 200 với body rỗng, sai kiểu dữ liệu, thiếu field bắt buộc, hoặc dữ liệu vô nghĩa. Assertion nâng cao đi sâu vào cấu trúc và ý nghĩa của dữ liệu.

Ba tầng assertion bạn nên viết

Hãy hình dung mỗi response cần được kiểm tra theo ba tầng, từ ngoài vào trong:

Tầng 1 — Structural (cấu trúc): kiểu dữ liệu, sự tồn tại của field, kiểu của mảng/object. Đây là nơi JSON Schema Validation tỏa sáng.

Tầng 2 — Value (giá trị): giá trị cụ thể có hợp lý không — email đúng định dạng, price là số dương, status nằm trong tập giá trị cho phép.

Tầng 3 — Relational (quan hệ): dữ liệu có nhất quán không — total bằng tổng các item.subtotal, createdAt nhỏ hơn updatedAt, số lượng phần tử khớp với field count.

JSON Schema Validation — trái tim của assertion cấu trúc

Đây chính là phần dàn ý gốc muốn bạn nắm. Thay vì viết hàng chục dòng pm.expect cho từng field, bạn định nghĩa một schema mô tả hình dạng dữ liệu mong đợi, rồi validate một phát:

var schema = {
    type: 'object',
    required: ['id', 'email', 'name'],
    properties: {
        id:    { type: 'integer' },
        email: { type: 'string', format: 'email' },
        name:  { type: 'string', minLength: 1 },
        age:   { type: 'integer', minimum: 0, maximum: 150 },
        role:  { type: 'string', enum: ['admin', 'customer', 'staff'] }
    }
};

pm.test("Response khớp schema user", function () { pm.response.to.have.jsonSchema(schema); });

Chỉ vài dòng nhưng bạn đã khóa chặt: id phải là số nguyên, email bắt buộc phải có, role chỉ được nhận ba giá trị cho phép. Nếu backend đổi id thành chuỗi hay quên trả email, test đỏ ngay lập tức. Postman dùng thư viện tv4/Ajv bên trong nên bạn viết theo chuẩn JSON Schema mà không cần cài gì thêm.

Một số thuộc tính hay dùng: required (danh sách field bắt buộc), enum (tập giá trị cho phép), minimum/maximum (khoảng số), minLength/maxLength (độ dài chuỗi), format (email, uri, date-time), và items để mô tả từng phần tử trong mảng.

Mock Server — API giả có thật

Một mock server trong Postman là một endpoint thật do Postman host, trả về response mẫu (gọi là examples) mà bạn định nghĩa trước. Frontend gọi vào URL mock đó như gọi API thật, nhận về đúng cấu trúc JSON đã thống nhất — mà backend chưa cần viết một dòng code nào.

Cơ chế: bạn tạo một request trong collection, thêm một hoặc nhiều saved example (mỗi example là một cặp request mẫu + response mẫu). Postman tạo cho collection đó một URL dạng https://<id>.mock.pstmn.io. Khi có request gọi tới, Postman so khớp path, method, và header rồi trả về example phù hợp nhất. Bạn có thể dùng header x-mock-response-code để ép mock trả về mã trạng thái cụ thể (ví dụ ép 404 để test luồng lỗi).

Tình huống thực tế

Ví dụ 1 — Tiki và cái bẫy "kiểu dữ liệu thầm lặng"

Một đội QA làm cho sàn thương mại điện tử kiểu Tiki phụ trách API /api/v2/products/{id}. Suốt ba tháng test của họ chỉ có status(200) và kiểm tra pm.expect(json.name).to.exist. Mọi thứ xanh. Rồi một ngày, team backend refactor: field price từ số 299000 được đổi thành chuỗi "299.000 ₫" để "tiện hiển thị". Test QA vẫn xanh vì name vẫn tồn tại và status vẫn 200.

Hậu quả: app mobile parse price thành số để tính giỏ hàng, gặp chuỗi có dấu chấm và ký tự nên tính sai tổng tiền, một số đơn hiển thị . Bug lọt tới production, mất gần một ngày để hotfix.

Sau sự cố, họ thêm JSON Schema:

var schema = {
    type: 'object',
    required: ['id', 'name', 'price', 'inStock'],
    properties: {
        id:      { type: 'integer' },
        name:    { type: 'string', minLength: 1 },
        price:   { type: 'number', minimum: 0 },
        inStock: { type: 'boolean' }
    }
};
pm.test("Product schema hợp lệ", function () {
    pm.response.to.have.jsonSchema(schema);
});

Bài học: assertion nông tạo cảm giác an toàn giả. Một dòng type: 'number' trong schema đủ để chặn đứng cả class lỗi "đổi kiểu dữ liệu thầm lặng".

Ví dụ 2 — Startup fintech Đà Nẵng: mock server cứu cả sprint

Một startup fintech ở Đà Nẵng xây tính năng "ví điện tử" mới. Frontend cần API POST /wallet/topup để làm màn hình nạp tiền, nhưng backend còn vướng tích hợp cổng thanh toán, dự kiến trễ 8 ngày. Nếu ngồi chờ, cả sprint hai tuần coi như mất một nửa.

QA lead dựng một mock server. Cả team backend và frontend cùng thống nhất "hợp đồng" response, rồi QA tạo hai example:

  • Example "success" (200): { "transactionId": "TXN123", "status": "success", "balance": 500000 }
  • Example "insufficient" (400) — dùng header x-mock-response-code: 400: { "error": "INSUFFICIENT_BALANCE", "message": "Số dư không đủ" }
Frontend trỏ biến môi trường baseUrl vào URL mock https://a1b2c3.mock.pstmn.io và code toàn bộ màn hình nạp tiền, xử lý cả luồng thành công lẫn lỗi. Tám ngày sau backend xong, họ chỉ việc đổi baseUrl sang server thật. Vì cùng chung một schema, việc chuyển đổi gần như không phát sinh lỗi tích hợp.

Bài học: mock server biến "hợp đồng API" thành thứ chạy được ngay, giúp frontend và QA làm việc song song với backend thay vì tuần tự.

Ví dụ 3 — Grab-style: khóa enum trạng thái đơn hàng

Một đội test hệ thống giao đồ ăn kiểu Grab có API trả trạng thái đơn: PENDING, PREPARING, DELIVERING, COMPLETED, CANCELLED. Một lần backend thêm trạng thái mới REFUNDED nhưng quên báo, khiến logic hiển thị icon trạng thái ở app bị vỡ.

QA thêm assertion enum vào schema:

properties: {
    status: { type: 'string', enum: ['PENDING','PREPARING','DELIVERING','COMPLETED','CANCELLED'] }
}

Ngay lần chạy đầu tiên sau khi backend deploy REFUNDED, test đỏ với thông báo giá trị không nằm trong enum. Đây chính xác là hành vi mong muốn: QA được thông báo về một thay đổi hợp đồng trước khi người dùng gặp lỗi. Họ ngồi lại với backend, thống nhất bổ sung REFUNDED vào cả schema lẫn app.

Bài học: enum trong schema biến test thành "còi báo động" cho mọi thay đổi hợp đồng ngoài kế hoạch.

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

Phần A — Viết bộ assertion nâng cao ba tầng

Bước 1. Mở tab Tests của request, gọi response về biến để tránh parse nhiều lần:

const json = pm.response.json();

Bước 2 — Tầng cấu trúc. Định nghĩa schema và validate:

const schema = {
    type: 'object',
    required: ['id', 'items', 'total'],
    properties: {
        id:    { type: 'integer' },
        total: { type: 'number', minimum: 0 },
        items: {
            type: 'array',
            minItems: 1,
            items: {
                type: 'object',
                required: ['sku', 'qty', 'subtotal'],
                properties: {
                    sku:      { type: 'string' },
                    qty:      { type: 'integer', minimum: 1 },
                    subtotal: { type: 'number', minimum: 0 }
                }
            }
        }
    }
};
pm.test("Cấu trúc order hợp lệ", () => {
    pm.response.to.have.jsonSchema(schema);
});

Bước 3 — Tầng giá trị. Kiểm tra ý nghĩa cụ thể:

pm.test("Tổng tiền là số dương", () => {
    pm.expect(json.total).to.be.above(0);
});

Bước 4 — Tầng quan hệ. Kiểm tra tính nhất quán giữa các field:

pm.test("Total khớp tổng subtotal", () => {
    const sum = json.items.reduce((acc, it) => acc + it.subtotal, 0);
    pm.expect(json.total).to.eql(sum);
});

Bước 5. Thêm assertion về hiệu năng và header (nhẹ nhàng, không thay JMeter):

pm.test("Phản hồi dưới 800ms", () => {
    pm.expect(pm.response.responseTime).to.be.below(800);
});
pm.test("Content-Type là JSON", () => {
    pm.expect(pm.response.headers.get('Content-Type')).to.include('application/json');
});

Phần B — Dựng một mock server

Bước 1. Chuẩn bị một request trong collection, ví dụ GET {{baseUrl}}/users/1.

Bước 2. Gửi request (hoặc tự soạn body), rồi bấm Save Response → Save as Example. Sửa body của example cho đúng "hợp đồng" đã thống nhất với team. Đặt status của example (200, 400...).

Bước 3. Vào menu collection, chọn Mock collection. Đặt tên, chọn môi trường lưu URL mock. Postman sinh ra URL dạng https://<id>.mock.pstmn.io.

Bước 4. Postman thường tự tạo biến {{url}} chứa địa chỉ mock. Trỏ baseUrl của bạn (hoặc của frontend) vào URL này rồi gọi thử — bạn sẽ nhận đúng example đã lưu.

Bước 5 — Test luồng lỗi. Thêm header khi gọi để ép mã trạng thái:

x-mock-response-code: 400
Postman sẽ trả example nào có status 400. Nhờ vậy bạn test cả happy path lẫn error path mà không cần backend.

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

Lỗi 1 — Viết assertion nhưng quên bọc trong pm.test(). Nếu bạn để trần pm.expect(...) mà không nằm trong pm.test(), khi thất bại nó chỉ ném lỗi làm dừng script chứ không hiện thành một dòng test đỏ/xanh rõ ràng. Luôn bọc mọi kỳ vọng trong pm.test("mô tả", () => { ... }).

Lỗi 2 — Schema không đặt required. Rất nhiều người viết properties đầy đủ nhưng quên required. Hậu quả: nếu API bỏ hẳn một field, schema vẫn pass vì "field không có thì không cần kiểm kiểu". required là thứ bắt lỗi thiếu field — đừng bỏ.

Lỗi 3 — Dùng additionalProperties sai chỗ. Nếu bạn muốn chặn field lạ xuất hiện, thêm additionalProperties: false. Nhưng cẩn thận: nhiều API trả thêm field metadata hợp lệ, bật cờ này sẽ làm test đỏ oan. Chỉ dùng khi bạn thực sự muốn khóa cứng cấu trúc.

Lỗi 4 — So sánh số thực bằng eql trực tiếp. Với tiền tệ và số thực, phép cộng dồn có thể lệch do dấu phẩy động (ví dụ 0.1 + 0.2). Nếu gặp, hãy làm tròn trước khi so: pm.expect(Math.round(json.total)).to.eql(Math.round(sum)).

Lỗi 5 — Mock server không khớp example. Nếu mock trả về sai example hoặc 404, thường do path/method không khớp, hoặc bạn có nhiều example và Postman chọn cái gần nhất theo thuật toán matching. Mẹo: đặt example rõ ràng theo từng path, và dùng x-mock-response-name để chỉ đích danh example muốn nhận.

Lỗi 6 — Quên rằng mock là dữ liệu tĩnh. Mock server không có logic — bạn POST gì nó vẫn trả example đã lưu. Đừng kỳ vọng nó tính toán. Nó để kiểm tra hình dạng và luồng, không phải nghiệp vụ.

Mẹo vàng: tách schema ra biến collection hoặc environment để tái sử dụng nhiều request. Bạn có thể lưu schema dưới dạng chuỗi JSON trong một biến, rồi JSON.parse(pm.collectionVariables.get('userSchema')) ở mỗi request. Cách này giúp một khi hợp đồng đổi, bạn chỉ sửa một chỗ.

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

  • Schema ba tầng. Lấy một API công khai (ví dụ https://jsonplaceholder.typicode.com/users/1). Viết một JSON Schema có ít nhất: 4 field required, một field dùng format: 'email', một field dùng enum. Sau đó thêm một assertion tầng-giá-trị và một assertion tầng-quan-hệ.
  • Bẫy kiểu dữ liệu. Cố tình đổi trong schema id thành type: 'string', chạy lại và quan sát thông báo lỗi. Ghi lại chính xác Postman báo gì — kỹ năng đọc lỗi schema rất quý khi debug.
  • Dựng mock cho luồng đăng nhập. Tạo request POST /login với hai example: một "success" (200, trả token) và một "wrong password" (401). Trỏ baseUrl vào mock, gọi cả hai luồng bằng header x-mock-response-code. Viết test kiểm schema cho cả hai response.
  • Nâng cao. Đưa schema ở bài 1 vào một collection variable, rồi dùng lại nó ở hai request khác nhau. Xác nhận rằng khi bạn sửa schema ở một chỗ, cả hai request đều áp dụng thay đổi.

Tóm tắt

Trong bài này bạn đã học cách biến test Postman từ "kiểm tra bề mặt" thành "khóa chặt hợp đồng dữ liệu". Hãy ghi nhớ ba ý cốt lõi:

  • Assertion ba tầng — cấu trúc, giá trị, quan hệ — mới thực sự bảo vệ bạn. status(200) là chưa đủ.
  • JSON Schema Validation với pm.response.to.have.jsonSchema(schema) là công cụ mạnh nhất để bắt lỗi đổi kiểu, thiếu field, và giá trị ngoài enum — chỉ với vài dòng khai báo.
  • Mock server biến hợp đồng API thành endpoint chạy được, giúp frontend/QA làm việc song song với backend và test cả luồng lỗi qua x-mock-response-code.
Ba tình huống của Tiki, startup fintech Đà Nẵng và hệ thống kiểu Grab cho thấy: những kỹ thuật này không phải lý thuyết — chúng trực tiếp chặn bug lọt production và cứu tiến độ sprint. Ở các bài sau, bạn sẽ tiếp tục đào sâu từng mảnh: cấu trúc collection, scripting sandbox, và cách chạy tự động bằng Newman. Nhưng nền tảng "assert cho sâu, mock để không phải chờ" sẽ theo bạn suốt sự nghiệp API testing.

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