Introduction
In our REST Assured series, we’ve explored topics like JSON Path Testing, Status Code Validation, and Response Specification, mastering various API testing techniques. Now, we’ll dive into XML Path (XPath), a powerful feature in REST Assured for extracting and validating data from XML responses. This guide demonstrates how to use XPath to navigate and test XML structures, ensuring accurate API behavior for XML-based systems. It’s designed for beginners and experienced developers, with clear explanations and practical examples.
Key Point: XML Path (XPath) in REST Assured enables you to query and validate specific elements in XML responses, simplifying data extraction and verification for XML-based APIs.
What is XML Path (XPath)?
XPath is a query language for XML, allowing you to select nodes, elements, attributes, or values within an XML document using a path-like syntax. In REST Assured, XPath is integrated to parse XML responses, enabling you to:
- Extract specific elements, attributes, or text values.
- Validate XML data using assertions.
- Handle nested structures and complex XML documents.
REST Assured’s XPath support leverages Java’s built-in XPath engine, making it straightforward to test XML-based APIs. Since many public testing APIs return JSON, we’ll use a mock XML response structure to simulate an API endpoint, representing a typical blog post resource. In real-world scenarios, you can target APIs that return XML, such as SOAP services or legacy REST APIs.
Setting Up for XML Testing
To use XPath, we’ll set up a Maven project with REST Assured, JUnit, and Allure for reporting. The setup is consistent with previous posts, with no additional dependencies needed for XPath, as it’s included in 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">
<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.1</allure.version>
<aspectj.version>1.9.22</aspectj.version>
</properties>
<dependencies>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>5.5.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.11.0</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.17.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.5.0</version>
<configuration>
<argLine>
-javaagent:${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar
</argLine>
</configuration>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>junit-jupiter-version</artifactId>
<version>${allure.version}</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-maven</artifactId>
<version>2.13.0</version>
<configuration>
<reportVersion>${allure.version}</reportVersion>
</configuration>
</plugin>
</plugins>
</build>
</project>
Since we’re using a mock XML response, no external API setup is required. For real-world testing, configure your project to target an XML-based API or use a local mock server (e.g., WireMock).
Using XPath in REST Assured Tests
Let’s explore how to use XPath to extract and validate data from XML responses in various scenarios. We’ll assume an API endpoint /posts/1
returns the following mock XML response:
<post>
<id>1</id>
<title>Sample Post</title>
<author>
<name>John Doe</name>
<email>john.doe@example.com</email>
</author>
<content>Post content here</content>
</post>
Example 1: Basic XPath Extraction
Extract and validate a single element from an XML response using XPath.
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.*;
import static org.junit.jupiter.api.Assertions.*;
@Feature("XML Path Testing")
public class BasicXPathTest {
@Test
@Description("Extract and validate a single element using XPath")
public void testExtractPostTitle() {
// Mock XML response for demonstration
String mockXml = "1 Sample Post John Doe Post content here ";
Response response = given()
.contentType("application/xml")
.body(mockXml)
.when()
.post("/echo") // Assuming an echo endpoint for mock
.then()
.statusCode(200)
.extract().response();
String title = response.xmlPath().getString("post.title");
assertEquals("Sample Post", title);
}
}
Explanation:
xmlPath().getString("post.title")
: Uses XPath to extract thetitle
element underpost
.assertRegex
: Validates the extracted value.- The mock XML simulates an API response; in production, replace with a real API call.
Important: XPath in REST Assured uses standard XPath syntax, such as/post/title
orpost.title
, to navigate XML elements.
Example 2: Navigating Nested XML Structures
Extract and validate nested elements or attributes using XPath.
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("XML Path Testing")
public class NestedXPathTest {
@Test
@Description("Extract and validate nested elements using XPath")
public void testExtractNestedAuthor() {
String mockXml = "1 Sample Post John Doe john.doe@example.com Post content here ";
Response response = given()
.contentType("application/xml")
.body(mockXml)
.when()
.post("/echo")
.then()
.statusCode(200)
.extract().response();
String authorName = response.xmlPath().getString("post.author.name");
String authorEmail = response.xmlPath().getString("post.author.email");
assertEquals("John Doe", authorName);
assertEquals("john.doe@example.com", authorEmail);
}
}
Explanation:
post.author.name
: Extracts thename
element underauthor
.post.author.email
: Extracts theemail
element underauthor
.- Assertions verify the extracted values.
Example 3: Handling XML Lists with XPath
Use XPath to extract and validate elements from a list in an XML response.
Assume an endpoint /posts
returns:
<posts>
<post>
<id>1</id>
<title>Post One</title>
</post>
<post>
<id>2</id>
<title>Post Two</title>
</post>
</posts>
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("XML Path Testing")
public class XmlListXPathTest {
@Test
@Description("Validate elements in an XML list using XPath")
public void testExtractListElements() {
String mockXml = "1 Post One 2 Post Two ";
given()
.contentType("application/xml")
.body(mockXml)
.when()
.post("/echo")
.then()
.statusCode(200)
.body("posts.post[0].id", equalTo("1"))
.body("posts.post[0].title", equalTo("Post One"))
.body("posts.post.size()", equalTo(2));
}
}
Explanation:
posts.post[0].id
: Accesses theid
of the firstpost
in the list.posts.post[0].title
: Validates thetitle
of the firstpost
.posts.post.size()
: Checks the number ofpost
elements.
Pro Tip: Use XPath’s list notation (e.g., post[0]
) to handle collections of elements in XML responses.
Example 4: Combining XPath with Response Specification
Integrate XPath validations with a ResponseSpecification for reusable tests.
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("XML Path Testing")
public class XPathWithSpecTest {
private ResponseSpecification responseSpec;
@BeforeEach
public void setup() {
responseSpec = new ResponseSpecBuilder()
.expectStatusCode(200)
.expectContentType("application/xml")
.expectBody("post.id", notNullValue())
.expectBody("post.title", notNullValue())
.build();
}
@Test
@Description("Validate XPath with Response Specification")
public void testXPathWithSpec() {
String mockXml = "1 Sample Post John Doe Post content here ";
given()
.contentType("application/xml")
.body(mockXml)
.when()
.post("/echo")
.then()
.spec(responseSpec)
.body("post.author.name", equalTo("John Doe"));
}
}
Explanation:
responseSpec
: Includes XPath validations forid
andtitle
.spec(responseSpec)
: Applies the specification to the test.- Additional XPath validation (
post.author.name
) is test-specific.
Integrating with Allure Reporting
Document XPath tests with Allure, attaching extracted data and response details.
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("XML Path Testing")
public class AllureXPathTest {
@Test
@Description("Validate XPath with Allure reporting")
public void testXPathWithAllure() {
String mockXml = "1 Sample Post John Doe Post content here ";
Response response = given()
.contentType("application/xml")
.body(mockXml)
.when()
.post("/echo")
.then()
.statusCode(200)
.body("post.title", equalTo("Sample Post"))
.extract().response();
String title = response.xmlPath().getString("post.title");
Allure.addAttachment("Extracted Title", "text/plain", title, ".txt");
Allure.addAttachment("Response Body", "application/xml", response.asString(), ".xml");
}
}
Explanation:
response.xmlPath()
: Creates an XmlPath object for XPath queries.Allure.addAttachment
: Attaches the extractedtitle
and full XML response to the Allure report.- Run
mvn clean test
andmvn allure:serve
to view the report.
Integrating with CI/CD
Add XPath tests to a GitHub Actions pipeline for automated execution.
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 XPath tests with
mvn clean test
. - Publishes Allure reports to GitHub Pages for visibility.
Tips for Beginners
- Learn XPath Syntax: Master basic XPath expressions (e.g.,
/post/title
,post/author/name
) and list access (e.g.,post[1]
). - Inspect XML Responses: Log responses with
log().all()
to understand XML structures before writing XPath queries. - Use Assertions: Combine XPath with Hamcrest matchers for robust validations.
- Test Real APIs: Use XML-based APIs or set up a mock server for realistic testing scenarios.
Troubleshooting Tip: If an XPath expression fails, verify the XML structure using log().all()
and check the XPath syntax against the document hierarchy.
What’s Next?
This post enhances our REST Assured series by introducing XML Path, a key tool for XML response validation. 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.