#### Overview

This blog post will delve deeper into using Cucumber for API testing, exploring advanced scenarios beyond basic GET and POST requests. It includes practical examples using the [reqres.in](https://reqres.in/) API to illustrate concepts.


#### Key Techniques

- **Testing Different HTTP Methods**: Learn to test PUT, DELETE, and PATCH requests for updating and removing resources.

- **Handling Authentication**: Understand how to manage Basic Auth, API keys, and tokens in your tests.

- **Validating Response Headers**: Ensure headers like Content-Type are correct.

- **Testing Error Responses**: Validate status codes and error messages for failed requests.

- **Using Scenario Outlines**: Efficiently test multiple cases with parameterized scenarios.


#### Practical Example

We'll provide a comprehensive example testing CRUD operations on a user API, ensuring you can apply these techniques in real projects.


---


### Survey Note: Detailed Analysis of Cucumber for API Testing


#### Introduction to Cucumber for API Testing


Welcome to the next installment of our Cucumber series! In this blog post, we'll delve deeper into using Cucumber for API testing, building upon our previous discussion of integrating Cucumber with REST-assured. We'll explore advanced scenarios such as testing various HTTP methods, handling authentication, validating response headers, and more. By the end of this post, you'll be equipped with the knowledge to write comprehensive and effective API tests using Cucumber, ensuring your APIs function as expected and meet user requirements.


#### Recap of Previous Integration


In our earlier post on integrating Cucumber with REST-assured, we covered the basics of setting up a project, writing feature files, and defining step definitions for simple GET and POST requests. We learned how to validate response status codes and extract data from JSON responses using tools like REST-assured. If you haven't read that post yet, I recommend starting there to get a solid foundation, as it detailed setting up a Maven project, creating feature files, and validating API responses with examples using [reqres.in](https://reqres.in/).


Now, let's build on that foundation by exploring more advanced API testing techniques with Cucumber.


#### Advanced API Testing Techniques


##### Testing Different HTTP Methods


Beyond GET and POST, APIs often support other HTTP methods like PUT, DELETE, and PATCH for updating and managing resources. Let's explore how to test these methods using Cucumber.


- **PUT Requests**: Used to update existing resources. For example, using the [reqres.in](https://reqres.in/) API, we can update a user's information. Here's a sample feature file snippet:


```gherkin

Scenario: Update user information

  Given the API endpoint is "[invalid url, do not cite]

  When the client sends a PUT request with the following data

    | name | Jane Doe |

    | job  | Engineer |

  Then the response status code should be 200

  And the response should contain the name "Jane Doe"

  And the response should contain the job "Engineer"

```


In the step definition, we use REST-assured to send the PUT request:


```java

@When("the client sends a PUT request with the following data")

public void sendPutRequest(DataTable dataTable) {

    Map<String, String> data = dataTable.asMaps().get(0);

    response = RestAssured.given()

        .contentType("application/json")

        .body(data)

        .put();

}

```


- **DELETE Requests**: Used to remove resources. For example:


```gherkin

Scenario: Delete a user

  Given the API endpoint is "[invalid url, do not cite]

  When the client sends a DELETE request

  Then the response status code should be 204

```


Step definition:


```java

@When("the client sends a DELETE request")

public void sendDeleteRequest() {

    response = RestAssured.delete();

}

```


- **PATCH Requests**: For partial updates, similar to PUT but with partial data. The approach is analogous, adjusting the feature file and step definitions accordingly.


##### Handling Authentication


Many APIs require authentication, such as Basic Auth, API keys, or OAuth tokens. In Cucumber tests, we can set up authentication in various ways to ensure secure access.


- **Basic Auth**: For APIs using Basic Authentication, we can configure it in the step definitions:


```gherkin

Given the client uses Basic Auth with username "user" and password "pass"

```


```java

@Given("the client uses Basic Auth with username {string} and password {string}")

public void setBasicAuth(String username, String password) {

    RestAssured.authentication = RestAssured.basic(username, password);

}

```


- **API Keys and Tokens**: For APIs requiring headers, we can set them in the request:


```gherkin

Given the client sets the header "Authorization" to "Bearer token123"

```


```java

@Given("the client sets the header {string} to {string}")

public void setHeader(String key, String value) {

    RestAssured.given().header(key, value);

}

```


However, for better reuse, consider managing authentication in hooks or context classes, applying it to scenarios tagged with `@auth`, as discussed in previous posts.


##### Validating Response Headers


In addition to checking the status code and body, validating response headers ensures the API returns expected metadata, such as content type or cache control.


Example feature file step:


```gherkin

Then the response header "Content-Type" should be "application/json"

```


Step definition:


```java

@Then("the response header {string} should be {string}")

public void verifyHeader(String headerName, String expectedValue) {

    String actualValue = response.getHeader(headerName);

    Assert.assertEquals("Header mismatch", expectedValue, actualValue);

}

```


This ensures the API returns the correct content type, enhancing test coverage.


##### Testing Error Responses


Testing how the API handles invalid requests or errors is crucial for robustness. This includes checking for appropriate status codes (e.g., 400, 401, 404) and error messages.


Example:


```gherkin

Scenario: Attempt to access protected resource without authentication

  Given the API endpoint is "[invalid url, do not cite]

  When the client sends a GET request

  Then the response status code should be 401

  And the response should contain the error message "Unauthorized"

```


Step definition:


```java

@Then("the response should contain the error message {string}")

public void verifyErrorMessage(String expectedMessage) {

    String actualMessage = response.jsonPath().getString("error");

    Assert.assertEquals("Error message mismatch", expectedMessage, actualMessage);

}

```


This validates the API's error handling, ensuring users receive clear feedback.


##### Using Scenario Outlines for Multiple Test Cases


Scenario Outlines allow efficient testing of multiple inputs and expected outputs, reducing repetition. For example, testing retrieval of different users:


```gherkin

Scenario Outline: Retrieve user by ID

  Given the API endpoint is "[invalid url, do not cite]

  When the client sends a GET request

  Then the response status code should be 200

  And the response contains "data.id" equals <id>


  Examples:

    | id |

    | 1  |

    | 2  |

    | 3  |

```


Step definitions remain as previously defined, with Cucumber replacing `<id>` with values from the Examples table. This approach is efficient for data-driven testing.


#### Best Practices for API Testing with Cucumber


To ensure your API tests are effective and maintainable, follow these best practices:


- **Keep Feature Files Readable**: Write scenarios from the user's perspective, focusing on what the API should do. For example, "Retrieve user by ID" is clearer than "Send GET request to /users/{id}".

- **Reuse Step Definitions**: Create generic steps that can be used across multiple scenarios, such as `the client sends a GET request` or `the response status code should be 200`.

- **Organize Tests**: Group related scenarios under features corresponding to API endpoints or functionalities, such as "User API Management" for CRUD operations.

- **Use Tags**: Categorize tests (e.g., `@smoke`, `@regression`) for selective execution, as shown in previous examples with `@create`, `@read`, etc.

- **Validate Both Success and Failure**: Ensure tests cover both positive scenarios (e.g., successful creation) and negative scenarios (e.g., unauthorized access).

- **Manage Test Data**: Use hooks or external data sources to handle test data setup and cleanup, especially for APIs that create or modify resources.


#### Comprehensive Example: Testing CRUD Operations


To illustrate these concepts, here's a complete feature file testing CRUD operations on a user API using [reqres.in](https://reqres.in/):


```gherkin

Feature: User API Management

  As a client, I want to manage users through the API.


  Background:

    Given the base URL is "[invalid url, do not cite]


  @create

  Scenario: Create a new user

    Given the endpoint is "/users"

    When the client sends a POST request with data

      | name | John Doe |

      | job  | Developer |

    Then the response status code is 201

    And the response contains "name" equals "John Doe"

    And the response contains "job" equals "Developer"


  @read

  Scenario Outline: Retrieve user by ID

    Given the endpoint is "/users/<id>"

    When the client sends a GET request

    Then the response status code is 200

    And the response contains "data.id" equals <id>

    Examples:

      | id |

      | 1  |

      | 2  |


  @update

  Scenario: Update user information

    Given the endpoint is "/users/2"

    When the client sends a PUT request with data

      | name | Jane Doe |

      | job  | Engineer |

    Then the response status code is 200

    And the response contains "name" equals "Jane Doe"

    And the response contains "job" equals "Engineer"


  @delete

  Scenario: Delete a user

    Given the endpoint is "/users/2"

    When the client sends a DELETE request

    Then the response status code is 204

```


Corresponding step definitions would include generic steps for setting endpoints, sending requests, and validating responses, as shown in previous examples. This example demonstrates comprehensive testing of the API, covering creation, retrieval, updates, and deletion, with tags for categorization.


#### Conclusion


Cucumber provides a powerful framework for API testing when combined with tools like REST-assured. By writing clear, behavior-driven tests, you can ensure your APIs function as expected and meet user requirements. Remember to keep your feature files focused on behavior, use reusable step definitions, and validate both successful and error scenarios to ensure comprehensive test coverage. In future posts, we'll explore more advanced topics, such as Cucumber for mobile testing or integrating with other CI/CD tools.