Introduction
In our REST Assured series, we’ve explored topics like XML Path Testing, JSON Path Testing, and Status Code Validation, mastering various API testing techniques. Now, we’ll dive into GPath Expressions, a versatile feature in REST Assured for querying and validating data from both JSON and XML responses using a unified syntax. This guide demonstrates how to use GPath to navigate and test response structures, ensuring robust API testing. It’s designed for beginners and experienced developers, with clear explanations and practical examples.
Key Point: GPath Expressions in REST Assured provide a flexible, Groovy-based syntax to query JSON and XML responses, simplifying data extraction and validation across different response formats.
What are GPath Expressions?
GPath Expressions are a Groovy-based query language used in REST Assured to navigate and extract data from JSON and XML responses. GPath combines elements of JSON Path and XPath, offering a consistent syntax for both formats. Key features include:
- Unified Syntax: Use similar expressions for JSON and XML, reducing the learning curve.
- Flexible Navigation: Access elements, attributes, arrays, and nested structures easily.
- Powerful Assertions: Validate extracted data using Hamcrest matchers or JUnit assertions.
REST Assured’s GPath support leverages Groovy’s GPath engine, making it ideal for APIs returning mixed response types. We’ll use https://jsonplaceholder.typicode.com
for JSON examples and a mock XML response for XML examples, simulating a typical API scenario.
Setting Up for GPath Testing
To use GPath, we’ll set up a Maven project with REST Assured, JUnit, and Allure for reporting. No additional dependencies are needed for GPath, as it’s built into REST Assured.
Here’s the pom.xml
, styled with your preferred Blogger format for XML syntax highlighting:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>rest-assured-tests</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<java.version>11</java.version>
<allure.version>2.27.0</allure.version>
<aspectj.version>1.9.22</aspectj.version>
</properties>
<dependencies>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>5.4.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest</artifactId>
<version>2.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-junit5</artifactId>
<version>${allure.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.5</version>
<configuration>
<argLine>
-javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
</argLine>
</configuration>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-maven</artifactId>
<version>2.12.0</version>
<configuration>
<reportVersion>${allure.version}</reportVersion>
</configuration>
</plugin>
</plugins>
</build>
</project>
For JSON examples, we’ll use https://jsonplaceholder.typicode.com
. For XML, we’ll use a mock response, as public XML-based REST APIs are less common. In production, target XML APIs or set up a mock server (e.g., WireMock).
Using GPath Expressions in REST Assured
Let’s explore how to use GPath to query and validate JSON and XML responses in various scenarios.
Example 1: Basic GPath Extraction for JSON
Extract and validate a single field from a JSON response using GPath.
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;
@Feature("GPath Expressions Testing")
public class BasicJsonGPathTest {
@Test
@Description("Extract and validate a JSON field using GPath")
public void testExtractJsonTitle() {
RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
given()
.log().all()
.when()
.get("/posts/1")
.then()
.statusCode(200)
.body("title", notNullValue())
.body("title", isA(String.class));
}
}
Explanation:
body("title", notNullValue())
: Uses the GPath expressiontitle
to validate thetitle
field in JSON.isA(String.class)
: Ensures the field is a string.- GPath uses dot notation for JSON, similar to JSON Path.
Important: GPath expressions for JSON are nearly identical to JSON Path expressions in REST Assured, using dot notation (e.g.,userId
) or array indexing (e.g.,[0]
).
Example 2: GPath for Nested JSON Structures
Extract and validate nested fields in a JSON response.
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.restassured.RestAssured;
import io.restassured.path.json.JsonPath;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.junit.jupiter.api.Assertions.*;
@Feature("GPath Expressions Testing")
public class NestedJsonGPathTest {
@Test
@Description("Extract and validate nested JSON fields using GPath")
public void testExtractNestedJson() {
RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
String response = given()
.log().all()
.when()
.get("/users/1")
.then()
.statusCode(200)
.extract().asString();
JsonPath gPath = new JsonPath(response);
String companyName = gPath.getString("company.name");
String city = gPath.getString("address.city");
assertEquals("Romaguera-Crona", companyName);
assertNotNull(city);
}
}
Sample Response JSON:
{
"id": 1",
"name": "Leanne Graham",
"address": {
"city": "Gwenborough",
"street": "Kulas Light"
},
"company": {
"name": "Romaguera-Crona"
}
}
Explanation:
gPath.getString("company.name")
: Extracts the nestedname
undercompany
.gPath.getString("address.city")
: Extracts the nestedcity
underaddress
.- Assertions verify the extracted values.
Example 3: GPath for XML Responses
Extract and validate data from a mock XML response using GPath.
Assume an endpoint /posts/1
returns:
<post>
<id>1</id>
<title>Sample Post</title>
<author>
<name>John Doe</name>
</author>
</post>
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.restassured.RestAssured;
import io.restassured.response.Response;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.junit.jupiter.api.Assertions.*;
@Feature("GPath Expressions Testing")
public class XmlGPathTest {
@Test
@Description("Extract and validate XML fields using GPath")
public void testExtractXml() {
String mockXml = "1 Sample Post John Doe ";
Response response = given()
.contentType("application/xml")
.body(mockXml)
.when()
.post("/echo")
.then()
.statusCode(200)
.extract().response();
String title = response.path("post.title");
String authorName = response.path("post.author.name");
assertEquals("Sample Post", title);
assertEquals("John Doe", authorName);
}
}
Explanation:
response.path("post.title")
: Uses GPath to extract thetitle
element.response.path("post.author.name")
: Extracts the nestedname
underauthor
.- GPath for XML uses dot notation, similar to JSON, making it intuitive.
Pro Tip: GPath’s unified syntax for JSON and XML reduces the need to switch between JSON Path and XPath, streamlining test code.
Example 4: GPath with Arrays
Query arrays in a JSON response using GPath.
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;
@Feature("GPath Expressions Testing")
public class ArrayGPathTest {
@Test
@Description("Validate JSON array elements using GPath")
public void testExtractJsonArray() {
RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
given()
.log().all()
.when()
.get("/posts")
.then()
.statusCode(200)
.body("[0].id", equalTo(1))
.body("[0].title", notNullValue())
.body("size()", greaterThan(0));
}
}
Explanation:
[0].id
: Accesses theid
of the first post in the array.[0].title
: Validates thetitle
is not null.size()
: Checks the array length.
Example 5: Combining GPath with Response Specification
Integrate GPath with a ResponseSpecification for reusable validations.
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.restassured.RestAssured;
import io.restassured.builder.ResponseSpecBuilder;
import io.restassured.specification.ResponseSpecification;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;
@Feature("GPath Expressions Testing")
public class GPathWithSpecTest {
private ResponseSpecification responseSpec;
@BeforeEach
public void setup() {
responseSpec = new ResponseSpecBuilder()
.expectStatusCode(200)
.expectContentType("application/json")
.expectBody("id", notNullValue())
.expectBody("title", notNullValue())
.build();
}
@Test
@Description("Validate GPath with Response Specification")
public void testGPathWithSpec() {
RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
given()
.log().all()
.when()
.get("/posts/1")
.then()
.spec(responseSpec)
.body("userId", equalTo(1));
}
}
Explanation:
responseSpec
: Uses GPath to validateid
andtitle
.spec(responseSpec)
: Applies the specification.- Additional GPath validation (
userId
) is test-specific.
Integrating with Allure Reporting
Document GPath tests with Allure, attaching extracted data and responses.
import io.qameta.allure.Allure;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.restassured.RestAssured;
import io.restassured.response.Response;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;
@Feature("GPath Expressions Testing")
public class AllureGPathTest {
@Test
@Description("Validate GPath with Allure reporting")
public void testGPathWithAllure() {
RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
Response response = given()
.log().all()
.when()
.get("/posts/1")
.then()
.statusCode(200)
.body("title", notNullValue())
.extract().response();
String title = response.path("title");
Allure.addAttachment("Extracted Title", "text/plain", title, ".txt");
Allure.addAttachment("Response Body", "application/json", response.asString(), ".json");
}
}
Explanation:
response.path("title")
: Extracts thetitle
using GPath.Allure.addAttachment
: Attaches the extractedtitle
and response body.- Run
mvn clean test
andmvn allure:serve
to view the report.
Integrating with CI/CD
Add GPath tests to a GitHub Actions pipeline.
Create or update .github/workflows/ci.yml
:
name: REST Assured CI Pipeline
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up JDK 11
uses: actions/setup-java@v4
with:
java-version: '11'
distribution: 'temurin'
- name: Cache Maven dependencies
uses: actions/cache@v4
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-maven-
- name: Run tests
run: mvn clean test
- name: Generate Allure report
run: mvn allure:report
- name: Upload Allure results
if: always()
uses: actions/upload-artifact@v4
with:
name: allure-results
path: target/allure-results
- name: Publish Allure report
if: always()
uses: simple-elf/allure-report-action@v1.7
with:
allure_results: target/allure-results
gh_pages: gh-pages
allure_report: allure-report
- name: Deploy report to GitHub Pages
if: always()
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: allure-report
Explanation:
- Runs GPath tests with
mvn clean test
. - Publishes Allure reports to GitHub Pages.
Tips for Beginners
- Master GPath Syntax: Learn dot notation (e.g.,
company.name
) and array access (e.g.,[0]
) for both JSON and XML. - Log Responses: Use
log().all()
to inspect response structures before writing GPath expressions. - Use Assertions: Combine GPath with Hamcrest matchers for robust validations.
- Test Both Formats: Practice with JSON and XML responses to leverage GPath’s flexibility.
Troubleshooting Tip: If a GPath expression fails, verify the response structure with log().all()
and check the expression against the JSON or XML hierarchy.
What’s Next?
This post enhances our REST Assured series by introducing GPath Expressions, a unified tool for querying JSON and XML. To continue your learning, consider exploring:
- GraphQL Testing: Testing GraphQL APIs with REST Assured.
- Advanced Allure Reporting: Customizing reports with environments and categories.
- End-to-End Testing: Combining REST Assured with Selenium for UI and API testing.