Postman Series - writing assertions and validating responses

Postman Series - writing assertions and validating responses

Β·

13 min read

Once you can run manual tests for your API endpoints you should start thinking of how to automate them. Automation makes verifying API behaviours straightforward and consistent while saving you much time.

Assertions for your tests are a great way to verify API behaviours. In postman, assertions are a key part of writing automated tests. They do the job of checking if a piece of code returns the expected output.

for example

pm.expect(response).to.equal(learning postman);
});

From the above assertion statement, we are trying to assert that (response) is equal to learning postman and it is returned as part of your response body.

Postman makes use of the Chai assertion library for creating assertion and BDD syntax to make tests readable and understandable.

The main reason for writing assertions and validating the responses in Postman is to verify that the actual and expected results have matched after the execution of a test. A typical postman assertion returns a Boolean value of either true or false. If the results do not match, the test will fail and we shall get the reason for failure from the output of the test.

Now, let's explore how we can use assertions to validate various aspects of an API response, ensuring its overall health.

Assertions in Postman

In Postman, assertions are checks you write to verify if the responses from your API calls match what you expect. They act like little tests within your larger test scripts.
Here's a breakdown of assertions in Postman:

  • Verification: Assertions ensure that the actual results returned by the API (like the response body or status code) align with the expected values you define in your tests.

  • Code-based: Assertions are written in JavaScript using the built-in Chai assertion library. Chai provides a clear and readable syntax for making assertions.

  • Pass/Fail: Each assertion evaluates to true or false. If the assertion is true (meaning the expected and actual results match), the test passes. If it's false (there's a mismatch), the test fails, indicating an issue with the API response.

  • Debugging: Failed assertions provide error messages that help pinpoint where the problem lies in the API's response. This aids in debugging and identifying API issues.

Essential Checks for Validating Responses

  1. Status code Validation

  2. Response body Validation

  3. Response Time Validation

  4. JSON schema Validation

  5. Headers Validation

Let's look at how we can use the above in our postman tests

Status code Validation:

Status codes are the foundation for understanding how your API responds to requests. Validating status codes is crucial for ensuring your API behaves as expected. They help identify whether an API call was successful, encountered a client-side error, or resulted in a server-side error.

  1. Importance of Status Code Validation

  2. Identifies Errors: You can quickly identify successful responses (200 OK) from errors by checking the status code. Specific error codes 404 Not Found or 401 Unauthorizedprovide clues about the nature of the problem.

  3. Verifies Functionality: Validating different status codes helps verify if your API endpoints handle various scenarios correctly. For instance, you were checking for a 201 Created status code after a POST request confirms successful resource creation.

  4. Improves Reliability: By ensuring your API returns the appropriate status codes, you build a more reliable API that applications can interact with predictably.

    A typical status code example is:

    A successfulGETrequest

    send a GET request to retrieve data from an API endpoint

    https://jsonplaceholder.typicode.com/posts

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

    Within the test tab input the code above and check your postman test result tab, this assertion indicates that the server successfully processed your request and is returning the requested data in the response body.

    However, pm.test is the recommended way to create a test case within Postman.

    pm.response.to.have.status(200); also uses the appropriate assertion to check for a status code of 200.
    Alternatively, you can use pm.expect(pm.response).to.have.status(200);

Response body Validation:

The response body is where the API returns the actual data you requested or the outcome of your API call in Postman. Validating the response body ensures that the API returns the expected data and structure.

  1. Importance of Response Body Validation:

    • Data Integrity: This ensures that the API returns the correct response body content, you can verify that the data returned by the API is accurate, complete, and matches your expectations.

    • Content Verification: Postman assertions allow you to verify the structure of the response body against the expected criteria, ensuring it adheres to a defined format (like JSON). It includes checking for specific data values, verifying the presence of certain fields, or ensuring the absence of undesired information.

    • Error Messages: writing assertions can help identify errors and unexpected behaviours within the response body. This also helps you debug your APIs better.

A typical response body validation example is:
A successfulGETrequest

https://swapi.dev/api/planets/3/

within this request, we will be validating the response body from the API

    const jsonData = pm.response.json();
    pm.test("Test data type of the response", () => {
      pm.expect(jsonData).to.be.an("object");
      pm.expect(jsonData.name).to.eql("Yavin IV");
      pm.expect(jsonData.rotation_period).to.eql("24");
      pm.expect(jsonData.orbital_period).to.eql("4818");
      pm.expect(jsonData.diameter).to.eql("10200");
      pm.expect(jsonData.climate).to.eql("temperate, tropical");
      pm.expect(jsonData.gravity).to.eql("1 standard");
      pm.expect(jsonData.terrain).to.eql("jungle, rainforests");
      pm.expect(jsonData.surface_water).to.eql("8");
      pm.expect(jsonData.population).to.eql("1000");
      pm.expect(jsonData.residents).to.eql([]);
      pm.expect(jsonData.films).to.be.a("array");
      pm.expect(jsonData.created).to.be.a("string");
      pm.expect(jsonData.edited).to.be.a("string");
      pm.expect(jsonData.url).to.be.a("string");
    });

Let's break it down step by step:

  1. const jsonData = pm.response.json();:

    • This line retrieves the response body from the API call and parses it as JSON data.

    • The parsed JSON object is then stored in the variable jsonData.

pm.test("Test data type of the response", () => { ... });:

  • This defines a test case named "Test data type of the response".

  • The arrow function syntax (=>) is used to define the test logic within curly braces{}.

  • pm.expect:

    • The test script utilizes multiple assertions using pm.expect to verify the structure and content of the jsonData object:

      • Data types: It checks if specific properties (like name, diameter) are of expected data types (object, string, array).

      • Specific values: It verifies that certain properties (like name, rotation_period) have the expected values ("Yavin IV", "24").

      • Empty array: It confirms that the residents property is an empty array ([]).

  1. Overall, the assertion written above was used to validate the response body that was returned from the API and also verify that they matched what was expected of it.

  2. Response time Validation: Response time is the time in which it takes the API to respond to a call. Validating response is necessary to deliver a good user experience. Also, these allow us to measure the API performance and also identify bottlenecks within the API infrastructure just in case it needs optimization.
    A typical response time example is:
    Within yourpre-request test tab, we will write our assertions and also in yourtest tab.

    Using this sample GET request url https://swapi.dev/api/planets/3/

     const startTime = new Date().getTime();
    
     function handleResponse(err, response) {
         const endTime = new Date().getTime();
         const responseTime = endTime - startTime;
         console.log("Response Time:", responseTime, "ms");
         pm.test("Response time is less than 400ms", function () {
             pm.expect(responseTime).to.be.below(400);
         });
     }
    
     pm.sendRequest(pm.request, handleResponse);
    

    This validation ensures that the response time of the API request is within acceptable limits (less than 400 milliseconds) and also logs the actual response time within the Postman console as shown in the third image. If the response time exceeds this it logs the exact response threshold, the test will fail.

    • const startTime = new Date().getTime();: This line captures the current timestamp in milliseconds new Date().getTime() and stores it in the startTime variable. This timestamp represents the moment before the request is sent.

    • function handleResponse(err, response) { ... }: This defines a function named handleResponse that takes two arguments:

      • err: This will contain any error information if the request fails.

      • response: This will contain the response object if the request is successful.

      • pm.expect(responseTime).to.be.below(400);: This line uses Chai assertions (pm.expect) to verify the response time. It checks if responseTime is less than 400 milliseconds (ms).

        • If the response time is indeed below 400ms, the test passes.

        • If the response time is greater than or equal to 400ms, the test fails, indicating a potentially slow response.

      • The handleResponse function acts as a callback that gets invoked after the response is received from the server. This ensures that the code responsible for processing the response (calculating time, adding assertions) only executes when the actual response is available.

JSON Schema validation:

JSON Schema validation is commonly used in APIs to validate request payloads and response bodies, ensuring that clients send and receive data in the expected format. A JSON Schema is written in JSON format and describes the expected structure of a JSON object.
If the JSON data passes all validation checks, it is considered valid according to the schema. However, if the data fails any validation checkβ€”for example, if a required property is missing or a property value does not match the expected typeβ€”the data is considered invalid, and validation errors are reported.

The JSON Schema structure uses keywords like the following:

  • type: Specifies the data type (string, number, object, array etc.)

  • properties: Defines the properties expected within an object and their data types.

  • required: Indicates which properties are mandatory within an object.

  • additional properties: Allows or disallows additional properties not explicitly defined in the schema.

A typical example of a JSON schema validation is a Successful GET request with a response body as shown in the Postman suite image below. We will be validating the response body data against the schema written inside this test tab.

https://swapi.dev/api/planets/3/

    var schema = {
          "type": "object",
          "properties": {
            "name": {
              "type": "string"
            },
            "data.rotation_period": {
              "type": "integer"
            },
            "data.orbital_period": {
              "type": "integer"
            },
            "diamater": {
              "type": "integer"
            },
            "climate": {
              "type": "string"
            },
            "gravity": {
                "type": "string"
            },
            "terrain": {
                "type": "string"
            },
            "data.surface_water": {
                "type": "integer"
            },
            "data.population": {
                "type": "integer"
            },
            "residents": {
                "type": "array"
            },
            "data.films": {
                "type": "string"
            },
            "created": {
                "type": "string"
            },
            "edited": {
                "type": "string"
            },
            "url": {
                "type": "string"
            }
          },
          "required": [
           "name",
        "rotation_period",
        "orbital_period",
        "diameter",
        "climate",
        "gravity",
        "terrain",
        "surface_water",
        "population",
        "residents",
        "films",
        "created",
        "edited",
        "url"
          ]
        }
    pm.test("Validate schema", () => {
    pm.response.to.have.jsonSchema(schema);
    });

Defining the JSON Schema:

  • The var schema block defines the JSON schema object that specifies the expected structure and data types for the response data.

  • type: "object": This indicates that the root level of the data should be an object.

  • properties: This object defines the expected properties within the response object. Each property name acts as a key, and its value is another object specifying details about the property:

    • Data Type: Keys like type: "string" or type: "integer" define the expected data type for each property.

    • Nested Properties: Properties like data.rotation_period use dot notation to specify nested properties within an object named "data".

  • required: This array lists all the mandatory properties that must be present in the response object.

  • The pm.test("Validate schema", () => { ... }); block defines a Postman test named "Validate schema".

  • Inside the test function:

    • pm.response.to.have.jsonSchema(schema);: This line is the key part for validation. It uses the pm.expect syntax and the to.have.jsonSchema assertion from Postman. This assertion checks if the response data (accessed through pm.response) conforms to the provided JSON schema (schema).

Headers Validation:

Headers are essential components of HTTP requests and responses. They carry crucial information about the request, response, and the resources involved. Validating headers in Postman is crucial for ensuring that APIs interact as expected, adhere to communication protocols, maintain security and integrity, and provide the necessary information for proper message handling and interpretation.

Importance of Header Validation:

  • Verifying Request Headers:

    • When a client sends an HTTP request, it includes headers that provide details such as the request method (e.g., GET, POST), content type (e.g., JSON, form data), authentication credentials, and any custom information required by the server. By validating request headers, you can confirm that your requests include necessary headers like authentication tokens or content type information, as mandated by the API.

Validating Response Headers:

  • When a server sends back an HTTP response, it includes headers that provide details such as the status code (e.g., 200 OK, 404 Not Found), content type, caching directives, and any additional information relevant to the response. Validating response headers allows you to verify if the server sends back the expected headers, such as content type or status codes. This helps ensure proper data interpretation and handling.

Identifying Communication Issues:

  • HTTP headers can also be used to convey custom information specific to the application or API being used. Incorrect or missing headers can sometimes indicate configuration problems or misunderstandings between your application and the API. Header validation helps catch these issues early on.

Here's a typical example of Header Validation

pm.test("Content-Type header is JSON", () => {
  pm.expect(pm.response.headers).to.have.property('Content-Type');
  pm.expect(pm.response.headers.get('Content-Type')).to.equal('application/json');
});
  • This script checks for the presence of a Content-Type header in the response.

  • It then verifies if the value of the Content-Type header is indeed application/json, indicating JSON data.

Here is another example below

pm.test("Verify response headers keys are present ", () => {
    pm.response.to.have.header("server");
    pm.response.to.have.header("Date");
    pm.response.to.have.header("Content-Type");
    pm.response.to.have.header("Transfer-Encoding");
    pm.response.to.have.header("Connection");
    pm.response.to.have.header("Vary");
    pm.response.to.have.header("X-Frame-Options");
    pm.response.to.have.header("ETag");
    pm.response.to.have.header("Allow");
    pm.response.to.have.header("Strict-Transport-Security");
});

  • The script defines a Postman test named "Verify response headers keys are present".

  • Inside the test function, multiple assertions are chained together using pm.response.to.have.header. This method is used to check for the existence of specific header names in the response.

  • Each assertion targets a particular header name:

    • server

    • Date

    • Content-Type

    • Transfer-Encoding

    • Connection

    • Vary

    • X-Frame-Options

    • ETag

    • Allow

    • Strict-Transport-Security

Overall, this code snippet contributes to a more robust testing process by ensuring the presence of essential headers in the API response.

Now, let's talk about Error Handling: Debugging Failed Assertions

Understanding Failure Messages:

Postman provides informative error messages when assertions fail. These messages pinpoint the exact line of code where the assertion failed and offer clues about the nature of the mismatch.

There are various reasons why your assertions can fail πŸ‘‡πŸ‘‡πŸ‘‡

  • Incorrect Assertions: Double-check your assertion syntax and ensure it accurately reflects your validation intent. Did you use the correct comparison operator (e.g., to.equal vs. to.be.above)?

  • Unexpected Response Data: The API response might not always conform to your expectations. Consider if the API might return different data structures or values under certain conditions.

  • Data Parsing Issues: If you're working with JSON data, ensure it's parsed correctly using pm.response.json(). Parsing errors can lead to assertion failures.

  • Typos and Missing Properties: Meticulously review your code for typos in variable names or property names within the response body. Missing properties can also cause assertions to fail.

Debugging Tips:

  • Console Logging: Use console.log statements to print out intermediate values like the response body or specific properties. This helps you inspect data using your Postman console at different stages of your test script and identify where things might be going wrong.

  • Test Breakdown: Break down complex assertions into smaller ones. This isolates the failing section and simplifies debugging.

  • Refer to Documentation: Consult the API documentation to understand the expected response format and data types. This helps you tailor your assertions accordingly.

  • Leverage Postman Features: Utilize Postman's built-in test runner and the "View Results" tab to visualize assertion failures and their corresponding error messages.

Good news πŸŽ‰ πŸŽ‰πŸŽ‰ Postman now has an AI inbuilt tool that you could use to write tests within your test collections or a stand-alone request called Postbot.

Postbot helps streamline your API development workflow in several ways:

  • Effortless Test Creation: Postbot suggests tests to validate your API's responses, saving you time writing them from scratch.

  • Smarter Scripting: Need help with scripting complex scenarios? Postbot offers guidance for writing JavaScript scripts within Postman.

  • Automated Draft Documentation: Say goodbye to manual documentation! Postbot analyzes your API interactions and generates draft documentation for a quick start.

  • Data Visualization Recommendations: Postbot recommends the most suitable visualizations for your response data, ensuring clear insights.

    I have taken the time to record a short video that explains how to use Postbot within Postman to generate scripts, write tests and modify them.

    %[loom.com/share/e08bb47a649343b1a9b22ba95171..

  • Tip: if you can't find this feature on your Postman, try to update or relaunch the app on your browser.

    Finally, we've explored the power of assertions in crafting robust and efficient API tests. By leveraging assertions for status code validation, response body checks, response time monitoring, JSON schema enforcement, and header verification, you gain a comprehensive understanding of your API's behaviour.

    Remember we also talked about the incredible AI assistant, Postbot, to further empower your workflow. Postbot can suggest tests, guide you with scripting complex scenarios, and even generate draft documentation – all to make your API development journey smoother and faster.

    So, the next time you want to test your APIs, remember the power of assertions and Postman's comprehensive toolkit. Together, they can help you build exceptional APIs with confidence and efficiency.