ارسال یک درخواست و دیدن پاسخ سبز، هنوز «تست API» نیست. یک تست مفید باید بگوید کدام رفتار را انتظار داریم، داده خروجی را بررسی کند، شناسه پویا را به درخواست بعدی بدهد، در اجرای تکراری همان نتیجه را بسازد و در CI با شکست درست متوقف شود.

در این آموزش Postman، یک جریان سفارش را از صفر می‌سازیم: Login، ایجاد سفارش، ذخیره order_id، بازیابی همان سفارش، آزمون منفی و Cleanup. سپس Collection را با داده CSV و Postman CLI اجرا می‌کنیم. آدرس‌ها و داده‌ها نمونه‌اند؛ آن‌ها را فقط روی API آزمایشی خود یا سامانه‌ای که مجوز تستش را دارید اجرا کنید.

در پایان می‌توانید:

  • Collection، Environment و Variable را درست تفکیک کنید؛
  • درخواست HTTP با Header، Auth و JSON Body بسازید؛
  • در Scripts → Post-response با pm.test Assertion بنویسید؛
  • Token و شناسه سفارش را بین درخواست‌ها عبور دهید؛
  • Collection را داده‌محور، از CLI و در CI/CD اجرا کنید؛
  • Secret، گزارش و داده آزمایشی را ایمن مدیریت کنید.

Postman چیست و این آموزش چه مرزی دارد؟

Postman محیطی برای ساخت، ارسال، سازماندهی و خودکارسازی درخواست‌های API است. این ابزار کمک می‌کند Request و Test کنار هم دیده شوند، اما کیفیت تست به سناریو، Assertion و داده شما وابسته است. مبانی HTTP، Contract، Authorization، Idempotency و انواع تست را در راهنمای جامع تست API بخوانید؛ این مقاله مشخصاً «پیاده‌سازی آن ایده‌ها در Postman» است.

Postman چه کاری را جایگزین نمی‌کند؟

  • چند درخواست دستی جای Test Strategy و پوشش ریسک را نمی‌گیرد؛
  • Mock Server اثبات نمی‌کند Backend واقعی درست است؛
  • Response Time یک درخواست، تست بار معتبر نیست؛
  • اسکریپت Postman جای Unit/Component Test نزدیک کد را نمی‌گیرد؛
  • Collection بدون Version Control و CI به Regression Suite قابل اتکا تبدیل نمی‌شود.

سناریوی نمونه: جریان سفارش فروشگاه

API نمونه این Endpointها را دارد:

POST   /v1/auth/login
POST   /v1/orders
GET    /v1/orders/{order_id}
DELETE /v1/test-data/orders/{order_id}

Endpoint آخر فقط برای Cleanup در محیط تست فرض شده است. در Production داده را با مسیر آزمایشی پاک نکنید. پیش از ساخت Request، انتظارهای جریان را بنویسید:

  • Login معتبر Token می‌دهد؛
  • ایجاد سفارش معتبر با 201 و شناسه غیرخالی پاسخ می‌دهد؛
  • سفارش بازیابی‌شده متعلق به همان کاربر و دارای همان کالا است؛
  • ورودی ناقص با خطای قراردادی مشخص رد می‌شود؛
  • کاربر دیگر سفارش را نمی‌بیند؛
  • Cleanup داده ساخته‌شده را حذف می‌کند.

نصب و ساخت Workspace امن

  1. نسخه Desktop یا Web را از منبع رسمی Postman باز کنید.
  2. یک Workspace مخصوص تیم و پروژه بسازید؛ دسترسی را کمینه نگه دارید.
  3. Collection جدیدی با نام Checkout API بسازید.
  4. Environmentهای local و staging را جدا تعریف کنید.
  5. از ابتدا مشخص کنید چه چیزی با Cloud همگام می‌شود و چه چیزی فقط Local می‌ماند.

رابط Postman تغییر می‌کند؛ در نسخه فعلی Script پاسخ در مسیر Scripts → Post-response قرار دارد. اگر نام یک Tab متفاوت بود، مستندات همان نسخه را بررسی کنید و منطق آموزش را دنبال کنید.

Collection را بر اساس جریان سازماندهی کنید

درخت پیشنهادی:

Checkout API
├── 00 Setup
│   └── Login test user
├── 01 Orders - happy path
│   ├── Create order
│   └── Get created order
├── 02 Orders - negative
│   ├── Create without product
│   └── Read another user's order
└── 99 Cleanup
    └── Delete test order

شماره‌ها ترتیب اجرا را واضح می‌کنند، اما بهتر است وابستگی پنهان نسازید. هر Folder باید هدف، پیش‌شرط و Cleanup خود را توضیح دهد. اگر مجموعه بزرگ شد، جریان‌های مستقل را جدا کنید تا Failure یک سناریو بقیه را مبهم نکند.

Variable و Environment در Postman

URL یا شناسه را در همه Requestها Hard-code نکنید. Postman Scopeهای Global، Collection، Environment، Data و Local دارد؛ اگر یک نام در چند Scope باشد، Scope باریک‌تر اولویت می‌گیرد.

مقدار Scope پیشنهادی دلیل
base_url Environment بین Local و Staging فرق دارد
api_version Collection برای همه محیط‌ها ثابت است
order_id Collection/Environment موقت بین درخواست‌های همان Run عبور می‌کند
product_id Data در هر Iteration از CSV می‌آید
API Key/Password Vault یا Secret محافظت‌شده CI نباید در Collection یا Export منتشر شود

Environment پایه

در Environment مربوط به Staging این متغیر را تعریف کنید:

base_url = https://api.staging.example.test

سپس URL را این‌طور بسازید:

{{base_url}}/v1/orders

طبق مستندات فعلی، مقدار Variable به‌صورت پیش‌فرض Local است و فقط در صورت اقدام صریح Share می‌شود. با این حال، هیچ Secret واقعی را داخل Collection/Environment Export، Screenshot، Console یا Git قرار ندهید.

ساخت اولین Request در Postman

Login کاربر آزمایشی

در Folder Setup یک HTTP Request ایجاد کنید:

  • Method: POST
  • URL: {{base_url}}/v1/auth/login
  • Header: Content-Type: application/json
  • Body → raw → JSON:
{
  "username": "{{test_username}}",
  "password": "{{vault:test-password}}"
}

سینتکس Vault نمونه فعلی Postman است. در Workspace و Plan شما ممکن است شیوه دسترسی یا قابلیت Cloud متفاوت باشد؛ Secret را با سیاست تیم و مستندات همان Runner تنظیم کنید.

پاسخ را فقط نگاه نکنید؛ تست بنویسید

در Scripts → Post-response این Assertionها را اضافه کنید:

pm.test("login returns 200", () => {
  pm.response.to.have.status(200);
});

pm.test("response is JSON", () => {
  pm.response.to.be.json;
});

const body = pm.response.json();

pm.test("access token exists", () => {
  pm.expect(body.access_token).to.be.a("string").and.not.empty;
});

pm.collectionVariables.set("access_token", body.access_token);

ذخیره Token باید بعد از اطمینان از ساختار پاسخ انجام شود. اگر JSON خراب باشد، خطای Parse می‌تواند Script را متوقف کند؛ در Suite جدی، Parse و پیام خطا را خوانا مدیریت کنید. در پایان Run نیز Token موقت را Unset کنید.

Authorization را یک بار در سطح Collection تعریف کنید

در Authorization خود Collection، نوع Bearer Token را انتخاب و مقدار زیر را وارد کنید:

{{access_token}}

Requestهای فرزند را روی Inherit auth from parent بگذارید. برای تست Guest یا Token نامعتبر، Auth همان Request را Override کنید. این ساختار هم تکرار را کم می‌کند و هم روشن می‌سازد کدام تست عمداً بدون Auth اجرا می‌شود.

ساخت درخواست ایجاد سفارش

Request دوم:

  • Method: POST
  • URL: {{base_url}}/v1/orders
  • Body:
{
  "items": [
    {
      "product_id": "{{product_id}}",
      "quantity": {{quantity}}
    }
  ],
  "delivery_city": "{{city}}"
}

عدد quantity بدون کوتیشن است تا JSON Number باقی بماند. اگر مقدار CSV غیرعددی شود، ممکن است JSON نامعتبر تولید شود؛ خود Request نهایی را در Console بررسی کنید.

Assertion روی Status، Header و منطق پاسخ

pm.test("order is created", () => {
  pm.response.to.have.status(201);
});

pm.test("content type is JSON", () => {
  pm.expect(pm.response.headers.get("Content-Type"))
    .to.include("application/json");
});

const order = pm.response.json();

pm.test("order contract has required fields", () => {
  pm.expect(order).to.have.property("id").that.is.a("string");
  pm.expect(order).to.have.property("status", "created");
  pm.expect(order).to.have.property("total").that.is.a("number");
  pm.expect(order).to.have.property("items").that.is.an("array").and.not.empty;
});

pm.collectionVariables.set("order_id", order.id);

نام تست باید رفتار را توضیح دهد، نه اینکه فقط بگوید Test ۱. یک Assertion شکست‌خورده باید به توسعه‌دهنده بگوید کدام Contract نقض شده است.

اعتبارسنجی JSON Schema

بررسی چند فیلد برای شروع خوب است، اما Contract ساختاری را می‌توان با JSON Schema سنجید:

const schema = {
  type: "object",
  required: ["id", "status", "total", "items"],
  properties: {
    id: { type: "string", minLength: 1 },
    status: { enum: ["created", "confirmed"] },
    total: { type: "number", minimum: 0 },
    items: {
      type: "array",
      minItems: 1
    }
  },
  additionalProperties: true
};

pm.test("response matches order schema", () => {
  pm.response.to.have.jsonSchema(schema);
});

additionalProperties: true در این مثال تغییر افزایشی را تحمل می‌کند. سخت‌گیری را با سیاست سازگاری API هماهنگ کنید. Schema جای Assertion منطق نیست؛ پاس شدن نوع Number ثابت نمی‌کند مبلغ درست محاسبه شده است.

Correlation؛ شناسه را به درخواست بعدی بدهید

پس از ذخیره order_id، Request بازیابی چنین می‌شود:

GET {{base_url}}/v1/orders/{{order_id}}

در Post-response، هم شناسه و هم داده کسب‌وکار را مقایسه کنید:

const order = pm.response.json();

pm.test("created order is returned", () => {
  pm.response.to.have.status(200);
  pm.expect(order.id)
    .to.equal(pm.collectionVariables.get("order_id"));
  pm.expect(order.items[0].product_id)
    .to.equal(pm.iterationData.get("product_id"));
});

این همان Correlation است: خروجی یک Request ورودی Request بعدی می‌شود. اگر ID را از نمونه قدیمی Hard-code کنید، تست ممکن است روی داده باقی‌مانده Pass شود و جریان فعلی را اصلاً نسنجد.

Pre-request Script را کجا به کار ببریم؟

Pre-request Script قبل از ارسال Request اجرا می‌شود. برای تولید شناسه همبستگی یا Timestamp مناسب است:

pm.variables.set(
  "correlation_id",
  pm.variables.replaceIn("{{$guid}}")
);

سپس Header زیر را اضافه کنید:

X-Correlation-Id: {{correlation_id}}

منطق کسب‌وکار پیچیده را بی‌دلیل داخل Script پنهان نکنید. اگر تولید Signature یا Auth سخت است، آن را در Helper قابل تست یا مسیر رسمی احراز هویت نگه دارید. Pre-request نباید با داده Production عملیات جانبی غیرمنتظره انجام دهد.

تست منفی و مرزی در Postman

Happy Path فقط بخشی از پوشش است. از تقسیم‌بندی هم‌ارزی و تحلیل مقدار مرزی برای انتخاب داده استفاده کنید:

ورودی/حالت انتظار نمونه
quantity=1 مرز معتبر و ایجاد سفارش
quantity=0 رد با خطای اعتبارسنجی قراردادی
quantity=max رفتار مطابق محدودیت موجودی/سیاست
بدون product_id رد، بدون Stack Trace
Token منقضی یا نامعتبر رد Authentication
سفارش کاربر دیگر رد Authorization بدون افشای داده
Idempotency Key تکراری بدون اثر مالی/سفارش تکراری طبق Contract

Status دقیق مانند ۴۰۰، ۴۰۱، ۴۰۳، ۴۰۴ یا ۴۲۲ باید از Contract خود API بیاید. برای نقش‌ها و ترکیب شرایط، جدول تصمیم تست بسیار مناسب است.

تست امنیت API در Postman

Postman برای آزمون کنترل‌های API مفید است، اما ابزار تست امنیت کامل نیست. حداقل این سناریوها را در Collection جدا و محیط مجاز بررسی کنید:

  • بدون Token، Token منقضی و Token نقش دیگر؛
  • دسترسی Object-level به شناسه متعلق به کاربر دیگر؛
  • Fieldهای اضافی که Client نباید مقداردهی کند؛
  • داده حساس در Response، Header و Error؛
  • Rate/Abuse Flow در حد مجاز RoE؛
  • Logout، Revocation و تغییر نقش؛
  • Redirect، Webhook و URL ورودی در Scope تعریف‌شده.

هیچ Payload مخرب یا بار حجیم را روی سرویس ثالث یا Production بدون مجوز اجرا نکنید. برای Threat Model، Rules of Engagement و گزارش امن یافته از راهنمای تست امنیت نرم‌افزار استفاده کنید.

اجرای داده‌محور با CSV یا JSON

فایل orders.csv را با UTF-۸ بسازید:

product_id,quantity,city
mobile-101,1,تهران
book-202,2,شیراز
audio-303,1,تبریز

در Collection Runner فایل را به‌عنوان Test Data انتخاب کنید. هر سطر یک Iteration است و در Script با pm.iterationData.get("product_id") قابل دسترسی است. برای متن دارای کاما، قواعد Quote CSV را رعایت کنید و پیش از Run پیش‌نمایش داده را ببینید.

داده خوب چه ویژگی دارد؟

  • قابل بازتولید و بدون اطلاعات واقعی مشتری است؛
  • حالت معتبر، نامعتبر و Boundary را پوشش می‌دهد؛
  • به محیط درست تعلق دارد؛
  • پس از Run قابل Cleanup است؛
  • ترتیب سطرها نتیجه را تغییر نمی‌دهد، مگر عمداً.

اگر State مشترک باعث برخورد اجرای موازی می‌شود، داده یکتا بسازید یا Namespace هر Run را با Correlation ID جدا کنید.

Collection Runner و ترتیب اجرا

Runner درخواست‌ها را در ترتیب Collection اجرا می‌کند. پیش از اتوماسیون:

  1. یک Iteration را دستی اجرا کنید؛
  2. موفقیت همه Assertionها را ببینید؛
  3. یک پاسخ را عمداً تغییر دهید و مطمئن شوید تست Fail می‌شود؛
  4. Console را برای Variable حل‌نشده یا Request اشتباه بررسی کنید؛
  5. Cleanup را حتی پس از شکست طراحی کنید.

اگر Request دوم بدون اولی اجرا نمی‌شود، پیش‌شرط را در توضیح ثبت کنید. برای Suiteهای بزرگ، Setup/Teardown مستقل و داده قابل ساخت بهتر از زنجیره‌ای بسیار طولانی است.

اجرای Collection با Postman CLI

نسخه فعلی Postman CLI می‌تواند Collection را از فایل محلی اجرا و گزارش CLI، JSON، JUnit یا HTML تولید کند:

postman collection run checkout.postman_collection.json   -e staging.postman_environment.json   -d orders.csv   -r cli,junit   --reporter-junit-export reports/postman.xml
  • -e: Environment File یا UID؛
  • -d: فایل داده Iteration؛
  • -r: Reporterهای مورد نیاز؛
  • خروجی JUnit: مناسب نمایش Test Report در CI.

اجرای فایل محلی برای Version Control ساده است. اگر با Collection ID وارد Postman شوید، نتیجه می‌تواند به Cloud ارسال شود؛ این رفتار را با سیاست داده سازمان هماهنگ کنید. روی --insecure برای خاموش‌کردن SSL Verification تکیه نکنید؛ CA محیط تست را درست پیکربندی کنید.

Newman هنوز کجا کاربرد دارد؟

Newman Runner خط فرمان Node.js برای Collectionهای Exportشده است و همچنان در مستندات رسمی پشتیبانی می‌شود:

npm install -g newman

newman run checkout.postman_collection.json   -e staging.postman_environment.json   -d orders.csv   --reporters cli,junit   --reporter-junit-export reports/newman.xml

برای پروژه جدید، Postman CLI و Newman را با نیازهای تیم مقایسه کنید. Postman CLI قابلیت‌های جدید پلتفرم را دنبال می‌کند؛ Newman برای Workflowهای موجود و اجرای فایل JSON آشناست، اما برخی قابلیت‌های Package Library را اجرا نمی‌کند. انتخاب را مستند و نسخه Runner را در CI Pin/کنترل کنید.

قرار دادن تست Postman در CI/CD

Collection را همراه Environment بدون Secret و داده مصنوعی در Repository نگه دارید. Pipeline باید:

  • Runner با نسخه کنترل‌شده نصب کند؛
  • Secret را از Secret Store محافظت‌شده دریافت کند؛
  • API آزمایشی و داده آماده را بررسی کند؛
  • Collection را اجرا و Exit Code را به وضعیت Job متصل کند؛
  • گزارش JUnit/JSON را Artifact کند؛
  • پس از Run داده و Token موقت را پاک کند.

همه تست‌های API را در یک Gate کند نگذارید. Smoke Contract/Authorization را در مسیر سریع و جریان‌های طولانی‌تر را زمان‌بندی‌شده اجرا کنید. راهنمای تست مداوم در CI/CD برای طراحی Lane، Gate و Failure Policy مناسب است؛ مبانی انتخاب تست‌های قابل نگهداری نیز در راهنمای اتوماسیون تست آمده است.

Mock Server؛ مفید اما با مرز روشن

Example Response می‌تواند پیش از آماده شدن Backend، قرارداد تعامل Frontend را قابل آزمایش کند. برای هر مثال، Status، Header و Body معنادار بسازید؛ فقط پاسخ ۲۰۰ خوش‌بینانه کافی نیست.

  • موفقیت، Validation Error، Unauthorized و Not Found را نمونه‌سازی کنید؛
  • Example را از Contract به‌روز نگه دارید؛
  • تست Consumer روی Mock را با تست Provider واقعی تکمیل کنید؛
  • Latency، State، Concurrency و خرابی Dependency واقعی را از Mock نتیجه نگیرید.

برای مرزهای سرویس و Test Doubleها، راهنمای تست یکپارچه‌سازی را ببینید.

تفسیر نتیجه و Debug شکست‌ها

Assertion Fail شده است

اول تفاوت Product Failure و Test Failure را بررسی کنید: Status/Body واقعی، Environment فعال، Scope متغیر و Test Data را ببینید. نام Assertion و Actual Value باید در تشخیص کمک کند. تست را فقط برای سبز شدن ضعیف نکنید.

متغیر حل نمی‌شود

  • Environment درست انتخاب شده است؟
  • Variable روشن و دارای Local Value است؟
  • نام مشابه در Scope باریک‌تر مقدار قدیمی ندارد؟
  • Script قبل از استفاده آن را Set می‌کند؟
  • Runner همان Environment/File را دریافت کرده است؟

دستی Pass، در Runner Fail

احتمالاً State یا ترتیب پنهان دارید: Token قبلی، Cookie محلی، Variable ذخیره‌شده یا داده باقی‌مانده. یک Run تمیز با Environment خالی و داده تازه اجرا کنید. در گزارش اجرای تست، Build، Environment و Data Version را نگه دارید؛ چارچوب Evidence در اجرای تست در STLC توضیح داده شده است.

اشتباهات رایج در تست API با Postman

  • فقط Status Code را بررسی می‌کنیم و Contract/Business Rule را نمی‌سنجیم؛
  • Token و Password را در Environment Export و Git قرار می‌دهیم؛
  • به Variableهای Global زیاد وابسته می‌شویم و Run قابل تکرار نیست؛
  • Collection فقط روی لپ‌تاپ سازنده Pass می‌شود؛
  • همه Requestها به یک داده مشترک و ناپایدار وصل‌اند؛
  • Cleanup نداریم و Run بعدی با داده قبلی تداخل دارد؛
  • Threshold زمان پاسخ دلخواه را به‌عنوان تست Performance استفاده می‌کنیم؛
  • Mock را شاهد صحت Provider می‌دانیم؛
  • گزارش CI شامل Header، Body یا Secret حساس می‌شود؛
  • Collection با تغییر Contract به‌روزرسانی و Review نمی‌شود.

ملاحظات تیم‌های ایرانی

  • فایل CSV و Assertionهای متن فارسی را با UTF-۸ و Unicode واقعی تست کنید؛
  • ریال/تومان، اعداد فارسی/لاتین، شماره موبایل و آدرس راست‌به‌چپ را در Contract و Boundary بگنجانید؛
  • درگاه پرداخت، پیامک و احراز هویت را فقط با Sandbox/Mock و مجوز Provider تست کنید؛
  • اگر Cloud Runner به شبکه خصوصی یا سرویس داخلی دسترسی ندارد، Runner/CI داخل شبکه کنترل‌شده اجرا کنید؛
  • پیش از وابستگی به قابلیت Cloud یا Plan پولی، دسترسی، سیاست داده و مسیر جایگزین محلی را ارزیابی کنید؛
  • ساعت و Timezone را در Timestampهای سفارش و گزارش روی UTC/قرارداد مشخص کنترل کنید.

چک‌لیست آموزش Postman

  • هر Collection هدف و Scope مشخص دارد.
  • Folderها بر اساس جریان و Happy/Negative/Cleanup جدا شده‌اند.
  • Base URL در Environment و مقدار ثابت در Collection است.
  • Secret در Vault یا Secret Store CI است، نه Export.
  • Auth در سطح مناسب تعریف و Overrideهای منفی واضح‌اند.
  • هر Request روی Status، Header، Contract و منطق لازم Assertion دارد.
  • شناسه پویا از Response استخراج می‌شود.
  • داده معتبر، نامعتبر و Boundary با CSV/JSON پوشش دارد.
  • Authorization کاربر دیگر و Error Handling آزموده می‌شود.
  • Run از وضعیت محلی قبلی مستقل است.
  • Cleanup حتی در شکست برنامه‌ریزی شده است.
  • CLI با Exit Code واقعی و گزارش JUnit در CI اجرا می‌شود.
  • گزارش‌ها Secret یا داده واقعی مشتری ندارند.
  • Collection، Environment Template و Data در Version Control و Review هستند.

سوالات متداول تست API با Postman

اسکریپت تست Postman را کجا بنویسیم؟

در رابط فعلی برای پاسخ HTTP به مسیر Scripts → Post-response بروید. با pm.test تست را نام‌گذاری و با pm.expect یا Assertionهای pm.response انتظار را بررسی کنید.

Postman CLI بهتر است یا Newman؟

هر دو Collection را از خط فرمان اجرا می‌کنند. Postman CLI مسیر فعلی قابلیت‌های پلتفرم و Reporterهای داخلی است؛ Newman Runner آشنای Node.js برای Collectionهای JSON و Workflowهای موجود است. محدودیت، سیاست Cloud، Runner و قابلیت مورد نیاز را مقایسه کنید.

چطور Token را بین Requestها منتقل کنیم؟

در Post-response پاسخ Login را Parse، وجود Token را Assert و آن را در Scope مناسب مانند Collection/Environment موقت Set کنید. Requestهای بعدی Auth را از همان Variable بخوانند و پس از Run آن را پاک کنید.

آیا Postman برای تست Performance کافی است؟

برای Smoke زمان پاسخ یا Run سبک مفید است، اما یک Assertion میلی‌ثانیه‌ای تست ظرفیت نیست. Load Model، Percentile، Throughput، زیرساخت مولد بار و مشاهده‌پذیری سرور به طراحی جدا نیاز دارند.

چرا Collection در CI Fail ولی دستی Pass می‌شود؟

معمولاً State محلی، Variable ذخیره‌شده، Environment متفاوت، ترتیب پنهان یا داده باقی‌مانده علت است. Run را با ورودی صریح و وضعیت تمیز بازتولید و Actual Request/Response را بدون افشای Secret مقایسه کنید.

جمع‌بندی

Postman زمانی از یک HTTP Client به ابزار تست تبدیل می‌شود که Collection شما انتظارهای روشن، داده کنترل‌شده، Correlation، Assertionهای معنادار و اجرای تکرارپذیر داشته باشد. از یک جریان کوچک شروع کنید، Fail شدن تست را عمداً امتحان کنید، Secret را از Artifact جدا نگه دارید و همان Collection را در CLI و CI اجرا کنید. سپس پوشش را بر اساس ریسک API توسعه دهید، نه بر اساس تعداد Requestهای ذخیره‌شده.

منابع رسمی

دیدگاهتان را بنویسید