How to Run API Tests in Azure DevOps Using Postman and Newman
Step-by-step guide to running Postman API test collections in Azure DevOps pipelines using Newman. Covers collection export, environment variables, YAML pipeline setup, HTML reporting, and CI integration best practices.
Postman is the most widely used API testing tool, and Newman is its command-line runner. Together, they integrate cleanly into Azure DevOps pipelines — allowing your Postman test collections to run automatically on every commit.
The Newman + Azure DevOps stack
Postman → Export collection + environment → Git repo
↓
Azure Pipelines → Newman runs collection → JUnit XML output
↓
PublishTestResults → Azure Test Plans
Step 1: Export your Postman collection
In Postman:
- Right-click your collection → Export
- Format: Collection v2.1
- Save as
tests/api/postman-collection.json
Export environment:
- Click the environment → Export
- Save as
tests/api/environments/staging.json
Commit both files to your repository. Never commit environments containing production credentials — use Azure DevOps variable substitution for sensitive values.
Step 2: Prepare the environment file for CI
The exported environment has hardcoded values. Replace secrets with placeholders:
{
"name": "staging",
"values": [
{ "key": "BASE_URL", "value": "{{BASE_URL}}", "enabled": true },
{ "key": "API_KEY", "value": "{{API_KEY}}", "enabled": true },
{ "key": "TEST_EMAIL", "value": "{{TEST_EMAIL}}", "enabled": true }
]
}Newman can override these with --env-var KEY=VALUE flags — values come from Azure DevOps pipeline variables.
Step 3: Pipeline YAML
trigger:
branches:
include: [main]
pool:
vmImage: ubuntu-latest
variables:
- group: api-test-secrets
steps:
- task: NodeTool@0
displayName: Setup Node.js
inputs:
versionSpec: '20.x'
- script: npm install -g newman newman-reporter-htmlextra
displayName: Install Newman
- script: mkdir -p test-results
displayName: Create results directory
- script: |
newman run tests/api/postman-collection.json \
--environment tests/api/environments/staging.json \
--env-var "BASE_URL=$(STAGING_URL)" \
--env-var "API_KEY=$(API_KEY)" \
--env-var "TEST_EMAIL=$(TEST_EMAIL)" \
--reporters cli,junit,htmlextra \
--reporter-junit-export test-results/newman-results.xml \
--reporter-htmlextra-export test-results/newman-report.html \
--reporter-htmlextra-title "API Test Report — $(Build.BuildNumber)" \
--bail
displayName: Run Postman/Newman tests
env:
STAGING_URL: $(STAGING_URL)
API_KEY: $(API_KEY)
TEST_EMAIL: $(TEST_EMAIL)
- task: PublishTestResults@2
displayName: Publish test results
inputs:
testResultsFormat: JUnit
testResultsFiles: test-results/newman-results.xml
testRunTitle: API Tests (Newman) — $(Build.BuildNumber)
mergeTestResults: true
condition: always()
- task: PublishPipelineArtifact@1
displayName: Upload HTML report
inputs:
targetPath: test-results/newman-report.html
artifact: api-test-report
condition: always()Newman flags explained
| Flag | Purpose |
|---|---|
--bail | Stop after first failure (remove for full run) |
--iteration-count N | Run collection N times |
--delay-request ms | Add delay between requests (rate limiting) |
--timeout-request ms | Request timeout |
--insecure | Ignore SSL cert errors (staging only) |
--verbose | Detailed request/response logging |
--env-var KEY=VALUE | Override environment variable |
Writing effective Postman tests
In Postman, add tests in the Tests tab of each request:
// Status code assertion
pm.test("Status code is 200", function () {
pm.response.to.have.status(200);
});
// Response time
pm.test("Response time under 500ms", function () {
pm.expect(pm.response.responseTime).to.be.below(500);
});
// Body structure
pm.test("Response has required fields", function () {
const body = pm.response.json();
pm.expect(body).to.have.property('id');
pm.expect(body).to.have.property('status');
pm.expect(body.status).to.equal('active');
});
// Save response value for next request
pm.test("Extract and save order ID", function () {
const body = pm.response.json();
pm.collectionVariables.set("ORDER_ID", body.id);
});The saved ORDER_ID is then available in subsequent requests as {{ORDER_ID}}.
Running different collections per environment
# Run smoke collection on every PR, full regression nightly
stages:
- stage: SmokeAPI
displayName: API Smoke Tests
jobs:
- job: Smoke
steps:
- script: |
newman run collections/smoke.json \
--env-var "BASE_URL=$(STAGING_URL)"
displayName: Smoke API tests
- stage: RegressionAPI
displayName: API Regression
condition: eq(variables['Build.Reason'], 'Schedule')
jobs:
- job: Regression
steps:
- script: |
newman run collections/regression.json \
--env-var "BASE_URL=$(STAGING_URL)" \
--iteration-count 1
displayName: Full API regressionCommon errors and fixes
Error: newman: command not found in pipeline
Fix: The install step (npm install -g newman) must precede the newman run. Check the step order and that Node.js is installed first.
Error: Error: ENOENT: no such file or directory, open 'test-results/newman-results.xml'
Fix: Newman only creates the output file if the directory exists. Add mkdir -p test-results before the newman command.
Error: Newman exits with code 1 but PublishTestResults still doesn't run
Fix: Add condition: always() to the PublishTestResults task. Without it, the task skips when the previous step fails.
Error: Environment variables show as {{VARIABLE_NAME}} in requests
Fix: Check that --env-var "KEY=VALUE" format is correct (no spaces around =). Also verify the variable name in Postman matches exactly (case-sensitive).
Error: newman-reporter-htmlextra: reporter not found
Fix: Install both newman and newman-reporter-htmlextra separately: npm install -g newman newman-reporter-htmlextra. They are separate packages.
Stay ahead in AI-driven QA
Get practical tutorials on test automation, AI testing, and quality engineering — straight to your inbox. No spam, unsubscribe any time.
Discussion
Sign in with GitHub to comment · powered by Giscus