Cucumber - API Testing
Cucumber: API Testing Explained
API testing with Cucumber allows you to validate the functionality, performance, and reliability of APIs by combining behavior-driven development (BDD) with API automation tools like RestAssured. This approach ensures your APIs meet business requirements in a human-readable format.
Why Use Cucumber for API Testing?
Cucumber’s Gherkin syntax enables non-technical stakeholders to understand and contribute to test scenarios. Integrating Cucumber with API testing tools helps:
- Bridge the gap between technical and non-technical teams.
- Ensure test cases align with business requirements.
- Validate APIs for functionality, data integrity, and edge cases.
Setting Up Cucumber for API Testing
1. Project Setup:
Create a Maven or Gradle project and add the following dependencies:
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>X.X.X</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>X.X.X</version>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>X.X.X</version>
</dependency>
2. Define Feature Files:
Write feature files to describe API tests in Gherkin syntax. For example, testing a user login API might look like this:
Feature: User Login API
Scenario: Valid login credentials
Given the login API endpoint is "https://api.example.com/login"
When the user submits valid credentials
Then the API response code should be 200
And the response body should contain "token"
3. Step Definitions:
Implement step definitions using RestAssured to handle HTTP requests and responses:
import io.restassured.RestAssured;
import io.restassured.response.Response;
import static org.hamcrest.Matchers.*;
public class ApiStepDefinitions {
private String endpoint;
private Response response;
@Given("the login API endpoint is {string}")
public void setApiEndpoint(String url) {
endpoint = url;
}
@When("the user submits valid credentials")
public void submitValidCredentials() {
response = RestAssured
.given()
.contentType("application/json")
.body("{ \"username\": \"user1\", \"password\": \"password123\" }")
.post(endpoint);
}
@Then("the API response code should be {int}")
public void verifyResponseCode(int statusCode) {
response.then().statusCode(statusCode);
}
@Then("the response body should contain {string}")
public void verifyResponseBody(String key) {
response.then().body("", hasKey(key));
}
}
4. Run the Tests:
Use a test runner class annotated with @RunWith(Cucumber.class)
to execute the scenarios:
import org.junit.runner.RunWith;
import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
@RunWith(Cucumber.class)
@CucumberOptions(features = "src/test/resources/features", glue = "stepdefinitions")
public class ApiTestRunner {
}
Real-World Scenario:
Imagine testing a product search API in an e-commerce platform. The API should return product details when valid search terms are provided.
Feature File:
Scenario: Search for a product by name
Given the search API endpoint is "https://api.example.com/search"
When the user searches for "laptop"
Then the API response code should be 200
And the response body should include a product with the name "laptop"
Step Definitions:
@When("the user searches for {string}")
public void searchProduct(String productName) {
response = RestAssured
.given()
.queryParam("query", productName)
.get(endpoint);
}
@Then("the response body should include a product with the name {string}")
public void verifyProductInResponse(String productName) {
response.then().body("products.name", hasItem(productName));
}
Best Practices
- Use environment variables to manage API endpoints and credentials.
- Test all possible response codes (e.g., 200, 400, 401, 500).
- Mock external APIs during development to isolate functionality.
- Validate response times for performance testing.