Blog / API Testing

Postman API testing by example

Postman is a tool that can help you develop APIs. From capturing and validating to testing requests and responses! You need to perform API testing to ensure that your Application Programming Interface or API is working correctly and as it should. This article shows you how API testing is done using Postman and JavaScript.

Written by Arman
Published On Sun Aug 15 2021
Last Updated Tue May 07 2024

Postman is a tool that can help you develop APIs. From capturing and validating to testing requests and responses! You need to perform API testing to ensure that your Application Programming Interface or API is working correctly and as it should. This article shows you how API testing is done using Postman and JavaScript.

Introduction

In this guide, I will explain how API testing in Postman works using JavaScript and provide you with the knowledge needed to create more effective API tests. So, let’s begin!

Writing Tests in Postman

The “Tests” Tab

In Postman, the “Tests” tab is where you write test scripts. This tab, located within each request, allows you to write JavaScript tests that evaluate the response of your API.

Tests Tab in Postman

Best Practices for Writing Tests

By following some best practices, you can make your tests better and more understandable so that your tests become more robust and reliable. Let’s check out some of these best practices:

1. Descriptive and Clear Test Names

  • Why It’s Important: Clear names make it easier to understand what each test checks at a glance, especially when reviewing test results or sharing tests with colleagues.
  • Example: Instead of naming a test “Test 1” or “Status Check,” use descriptive names like “Verify Status Code is 200 for User Endpoint” or “Ensure Response Time is Below 500ms.”

2. Testing One Concern Per Test

  • Why It’s Important: Focusing on one assertion per test simplifies troubleshooting and understanding test results. If a test fails, you know just what went wrong.

  • Example: Separate them instead of combining status code and response time checks in one test:

    // Test for status code
    pm.test("Status code is 200", function () {
    pm.response.to.have.status(200);
    });
    
        // Test for response time
        pm.test("Response time is less than 500ms", function () {
            pm.expect(pm.response.responseTime).to.be.below(500);
        });
        ```
    

3. Use Assertive Language

  • Why It’s Important: Assertive language in tests makes them more readable and intention-driven. It clarifies the purpose of the test.
  • Example: Use assertive phrases like expect(response).to.contain... or response.should.have..., clearly stating the test’s expectations.

4. Organize Tests Logically

  • Why It’s Important: Grouping related tests or organizing them logically can make your testing suite more understandable and maintainable.
  • Example: If testing various aspects of a user API, group tests related to user creation, user data retrieval, and user deletion together.

5. Handle Different Test Scenarios

  • Why It’s Important: Testing only the “happy path” can leave critical bugs in edge cases. It’s essential to test various scenarios, including potential error conditions.

  • Example: Alongside testing a successful API call, write tests for scenarios like invalid inputs, unauthorized access, or server errors.

    // Test for invalid input
    pm.test("Response for invalid input is 400", function () {
      pm.expect(pm.response.code).to.eql(400);
    });
    

6. Maintainability and Reusability

  • Why It’s Important: Tests should be easy to update and reusable for different scenarios. This practice saves time and effort in the long run.
  • Example: Create reusable functions for common test assertions. Call these functions with different parameters as needed rather than writing the same code in multiple tests.

7. Commenting and Documentation

  • Why It’s Important: Good comments and documentation make it easier for others (and your future self) to understand the purpose and mechanics of your tests.
  • Example: Add comments to clarify complex logic or the reason behind specific test cases, especially when testing less obvious or intricate API parts.

Using expect for Assertions

Introduction to Chai Library

Chai is an assertion library used in JavaScript for test-driven development (TDD) and behaviour-driven development (BDD). In API testing using Postman, Chai offers a set of assertions for validating the API requests and responses by ensuring they meet the expected criteria.

Purpose of Assertion Libraries

An assertion library like Chai serves a fundamental role in testing:

  1. Verification: It provides a systematic way to check whether the output of a code block (or, in this case, an API response) matches the expected result.
  2. Readability: Chai’s syntax is designed to be human-readable, making tests easier to write and understand.
  3. Robust Testing: Covering a wide range of assertion types allows testers to write comprehensive tests covering various aspects of the API response.

Using expect in Postman

Within Postman, ‘expect’ statements allow you to perform detailed checks on your response data. For example:

pm.test("Response should be an object", function () {
  pm.expect(pm.response.json()).to.be.an("object");
});

Key Elements to Validate

  • Status Code: Ensure your API returns the correct status code, indicating the request’s success or failure.
  • Response Body: Validate the structure and data of the response body to ensure your API returns the expected data.
  • Response Headers: Checking headers can verify content type, caching rules, and more.
  • Response Time: Ensuring your API responds in a timely manner is crucial for performance.

Using pm.response in Postman for API Testing

pm.response is an important object in Postman scripting that gives you much information about the response returned from your API request. By using pm.response correctly and effectively, you can improve your API testing because this object allows you to access and validate various aspects of the response data. Here’s a more detailed look at utilizing pm.response in your tests:

Accessing Response Attributes

pm.response contains several properties and methods that give you access to different parts of the API response, such as the status code, response time, headers, and body. Here’s how you can use them:

  1. Status Code: Access the status code of the response to verify if the API request was successful.

    let statusCode = pm.response.code;
    pm.expect(statusCode).to.eql(200);
    
  2. Response Time: Check how long the API took to respond, which is crucial for performance testing.

    let responseTime = pm.response.responseTime;
    pm.expect(responseTime).to.be.below(500); // time in milliseconds
    
  3. Headers: Examine the response headers for important metadata like content type, caching policies, and more.

    let contentTypeHeader = pm.response.headers.get("Content-Type");
    pm.expect(contentTypeHeader).to.include("application/json");
    
  4. Body: The response body contains the data returned by the API. You can parse this data and make assertions based on your API’s expected output.

    let responseBody = pm.response.json(); // For JSON response
    pm.expect(responseBody).to.have.property("name", "John Doe");
    

Using pm.response for Complex Validations

Beyond simple assertions, pm.response can be used for more complex validations:

  • Validating Response Structure: Ensure the response body follows a specific schema or structure.
  • Conditional Testing: Perform different tests based on certain response conditions. For example, if the status code is 200, check one set of criteria; if it’s 400, check another.
  • Dynamic Data Validation: Sometimes, responses contain dynamic data (like timestamps or unique IDs). Use pm.response to validate the format of these dynamic elements without hardcoding the values.

Best Practices with pm.response

  • Readability: Keep your tests readable and straightforward. Complex logic can make tests more complicated to understand and maintain.
  • Error Handling: Include error handling in your tests. For example, check if the response body is present before trying to parse it.
  • Consistency: Be consistent in how you use pm.response across different tests. This consistency helps in maintaining and scaling your test suite.

Validation Examples

Validating Response Status Code

  • Validate single status code:

    pm.test("the endpoint returns the expected status code", () => {
      // change 200 to the response code you expect
      const expectedStatusCode = 200;
    
      pm.response.to.have.status(expectedStatusCode);
    });
    
  • Validate multiple status codes:

    // change 200 or 201 to the response code you expect
    pm.test("Status code is 200 or 201", function () {
      pm.expect(pm.response.code).to.be.oneOf([200, 201]);
    });
    

Validating Response Time

// change 500 to the expected response time
pm.test("Response time is less than 500ms", function () {
  pm.expect(pm.response.responseTime).to.be.below(500);
});

Validating Response Headers

pm.test("Content-Type is application/json", function () {
  pm.response.to.have.header("Content-Type", "application/json");
});

Validating Response Body

Postman test to check field value in response

We can validate the value of both id and name fields of the https://rickandmortyapi.com/api/character/1 using the test below.

pm.test("API response contains the expected fields", () => {
  const response = pm.response.json();

  // the line below checks value of the id field is 1 (number).
  pm.expect(response).to.have.property("id", 1);

  // the line below checks value of the name field is Rick Sanchez (string).
  pm.expect(response).to.have.property("name", "Rick Sanchez");
});

Test if Response Body matches schema

Testing if the response body matches a specific schema

pm.test("Body matches schema", function () {
  let schema = {
    type: "object",
    properties: {
      id: { type: "integer" },
      name: { type: "string" },
      status: { type: "string" },
      species: { type: "string" },
      type: { type: "string" },
      gender: { type: "string" },
      origin: {
        type: "object",
        properties: {
          name: { type: "string" },
          url: { type: "string" },
        },
        required: ["name", "url"], // Added required property for origin
      },
      location: {
        type: "object",
        properties: {
          name: { type: "string" },
          url: { type: "string" },
        },
        required: ["name", "url"], // Added required property for location
      },
      image: { type: "string" },
      episode: {
        type: "array",
        items: { type: "string" },
      },
      url: { type: "string" },
      created: { type: "string" },
    },
    required: [
      "id",
      "name",
      "status",
      "species",
      "type",
      "gender",
      "origin",
      "location",
      "image",
      "episode",
      "url",
      "created",
    ],
  };
  pm.expect(pm.response.json()).to.be.jsonSchema(schema);
});

Test if nested field value is available in response

The script below step works for fields at the root of the response. What if we wanted to test the name field under the origin field. We can tweak the script to support fields at any level.

pm.test("API response contains the expected fields", () => {
  const response = pm.response.json();

  // the line below checks value of the id field is 1 (number).
  pm.expect(response).to.have.nested.property("id", 1);

  // the line below checks value of the name field is Rick Sanchez (string).
  pm.expect(response).to.have.nested.property("name", "Rick Sanchez");

  // the line below checks value of the origin.name field is Earth (C-137) (string).
  pm.expect(response).to.have.nested.property("origin.name", "Earth (C-137)");
});

Check nested array value in response

We can take it further and use the same technique to validate the value of items in the array. For example, we can use the script below to check the value of the second item in the episode array of the https://rickandmortyapi.com/api/character/1 endpoint.

pm.test("API response contains the expected fields", () => {
  const response = pm.response.json();

  // the line below checks the value of the episode field at index 0 is "https://rickandmortyapi.com/api/episode/1".
  pm.expect(response).to.have.nested.property("episode.0", "https://rickandmortyapi.com/api/episode/1");
});

No code API testing using Testfully

Testfully is a leading API testing & monitoring tool and a great Postman alternative for API testing. The below video is a quick demo of Testfully and how you can use it to test your APIs without writing code.

Conclusion

As you saw, you can significantly improve your API testing process by using JavaScript in your Postman workflow. The examples and practices that we went through can help you develop comprehensive and reliable API tests. Try them and tailor them to fit your specific testing needs. Happy testing!

Comments, Questions, or Feedback? Post it here!

0 comments

Testfully is a bootstrapped startup from Sydney, Australia.
We're funded by our supportive & amazing customers.

The word `testfully` is a registered trademark of Testfully Pty Ltd.