by thetestingacademy
Production-grade REST API automation framework with REST Assured, POJO serialization using GSON, PayloadManager pattern, E2E integration workflows with TestNG ITestContext, and Allure reporting.
npx @qaskills/cli add restassured-api-frameworkAuto-detects your AI agent and installs the skill. Works with Claude Code, Cursor, Copilot, and more.
You are an expert QA automation engineer specializing in REST API automation with Java using REST Assured. When the user asks you to build, review, or debug an API test automation framework, follow these detailed instructions covering POJO-based request/response handling, PayloadManager pattern, E2E integration workflows, and advanced reporting.
@SerializedName and @Expose annotations for type-safe JSON handling.src/
main/java/com/thetestingacademy/
endpoints/
APIConstants.java # Base URL and endpoint paths
modules/
PayloadManager.java # Payload creation and response parsing
pojos/
request/
Auth.java # Authentication POJO
Booking.java # Booking request POJO
Bookingdates.java # Nested dates POJO
reponse/
BookingResponse.java # Booking response POJO
TokenResponse.java # Token response POJO
test/java/com/thetestingacademy/
base/
BaseTest.java # Setup, teardown, token helper
asserts/
AssertActions.java # Custom assertion methods
tests/
crud/
TestHealthCheck.java # API health check
TestCreateToken.java # Token creation test
TestCreateBooking.java # CRUD booking tests
e2e_integration/
TestIntegrationFlow1.java # Full E2E workflow (Create→Read→Update→Delete)
TestIntegrationFlow2.java # Alternate integration flow
sample/
TestIntegrationSample.java # Test template
resources/
data.properties # Configuration
testng.xml # Default test suite
testng_e2e.xml # E2E integration suite
pom.xml
<dependencies>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>5.5.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>json-schema-validator</artifactId>
<version>5.4.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.10.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-testng</artifactId>
<version>2.27.0</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.25.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.3</version>
</dependency>
<dependency>
<groupId>com.github.javafaker</groupId>
<artifactId>javafaker</artifactId>
<version>1.0.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.24.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.1.2</version>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>testng.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</plugin>
</plugins>
</build>
package com.thetestingacademy.endpoints;
public class APIConstants {
public static String BASE_URL = "https://restful-booker.herokuapp.com";
public static String CREATE_UPDATE_BOOKING_URL = "/booking";
public static String AUTH_URL = "/auth";
public static String PING_URL = "/ping";
}
package com.thetestingacademy.pojos.request;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Auth {
@SerializedName("username")
@Expose
private String username;
@SerializedName("password")
@Expose
private String password;
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
}
package com.thetestingacademy.pojos.request;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Booking {
@SerializedName("firstname")
@Expose
private String firstname;
@SerializedName("lastname")
@Expose
private String lastname;
@SerializedName("totalprice")
@Expose
private Integer totalprice;
@SerializedName("depositpaid")
@Expose
private Boolean depositpaid;
@SerializedName("bookingdates")
@Expose
private Bookingdates bookingdates;
@SerializedName("additionalneeds")
@Expose
private String additionalneeds;
// Getters and Setters
public String getFirstname() { return firstname; }
public void setFirstname(String firstname) { this.firstname = firstname; }
public String getLastname() { return lastname; }
public void setLastname(String lastname) { this.lastname = lastname; }
public Integer getTotalprice() { return totalprice; }
public void setTotalprice(Integer totalprice) { this.totalprice = totalprice; }
public Boolean getDepositpaid() { return depositpaid; }
public void setDepositpaid(Boolean depositpaid) { this.depositpaid = depositpaid; }
public Bookingdates getBookingdates() { return bookingdates; }
public void setBookingdates(Bookingdates bookingdates) { this.bookingdates = bookingdates; }
public String getAdditionalneeds() { return additionalneeds; }
public void setAdditionalneeds(String additionalneeds) { this.additionalneeds = additionalneeds; }
}
package com.thetestingacademy.pojos.request;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Bookingdates {
@SerializedName("checkin")
@Expose
private String checkin;
@SerializedName("checkout")
@Expose
private String checkout;
public String getCheckin() { return checkin; }
public void setCheckin(String checkin) { this.checkin = checkin; }
public String getCheckout() { return checkout; }
public void setCheckout(String checkout) { this.checkout = checkout; }
}
package com.thetestingacademy.pojos.reponse;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class TokenResponse {
@SerializedName("token")
@Expose
private String token;
public String getToken() { return token; }
public void setToken(String token) { this.token = token; }
}
package com.thetestingacademy.pojos.reponse;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import com.thetestingacademy.pojos.request.Booking;
public class BookingResponse {
@SerializedName("bookingid")
@Expose
private Integer bookingid;
@SerializedName("booking")
@Expose
private Booking booking;
public Integer getBookingid() { return bookingid; }
public void setBookingid(Integer bookingid) { this.bookingid = bookingid; }
public Booking getBooking() { return booking; }
public void setBooking(Booking booking) { this.booking = booking; }
}
The PayloadManager centralizes all payload creation, serialization, and deserialization. This keeps test classes clean and focused on assertions.
package com.thetestingacademy.modules;
import com.github.javafaker.Faker;
import com.google.gson.Gson;
import com.thetestingacademy.pojos.reponse.BookingResponse;
import com.thetestingacademy.pojos.reponse.TokenResponse;
import com.thetestingacademy.pojos.request.Auth;
import com.thetestingacademy.pojos.request.Booking;
import com.thetestingacademy.pojos.request.Bookingdates;
public class PayloadManager {
Gson gson;
Faker faker;
// --- Serialization: Java Object → JSON String ---
public String createPayloadBookingAsString() {
Booking booking = new Booking();
booking.setFirstname("Pramod");
booking.setLastname("Dutta");
booking.setTotalprice(112);
booking.setDepositpaid(true);
Bookingdates bookingdates = new Bookingdates();
bookingdates.setCheckin("2024-02-01");
bookingdates.setCheckout("2024-02-10");
booking.setBookingdates(bookingdates);
booking.setAdditionalneeds("Breakfast");
gson = new Gson();
return gson.toJson(booking);
}
// Payload with random data using JavaFaker
public String createPayloadBookingFakerJS() {
faker = new Faker();
Booking booking = new Booking();
booking.setFirstname(faker.name().firstName());
booking.setLastname(faker.name().lastName());
booking.setTotalprice(faker.random().nextInt(1, 1000));
booking.setDepositpaid(faker.random().nextBoolean());
Bookingdates bookingdates = new Bookingdates();
bookingdates.setCheckin("2024-02-01");
bookingdates.setCheckout("2024-02-10");
booking.setBookingdates(bookingdates);
booking.setAdditionalneeds("Lunch");
gson = new Gson();
return gson.toJson(booking);
}
// Edge case payload with non-ASCII characters
public String createPayloadBookingAsStringWrongBody() {
Booking booking = new Booking();
booking.setFirstname("会意; 會意");
booking.setLastname("Test");
booking.setTotalprice(112);
booking.setDepositpaid(true);
Bookingdates bookingdates = new Bookingdates();
bookingdates.setCheckin("5025-02-01");
bookingdates.setCheckout("5025-02-10");
booking.setBookingdates(bookingdates);
booking.setAdditionalneeds("Breakfast");
gson = new Gson();
return gson.toJson(booking);
}
// Full update payload
public String fullUpdatePayloadAsString() {
Booking booking = new Booking();
booking.setFirstname("UpdatedFirstName");
booking.setLastname("UpdatedLastName");
booking.setTotalprice(500);
booking.setDepositpaid(false);
Bookingdates bookingdates = new Bookingdates();
bookingdates.setCheckin("2024-03-01");
bookingdates.setCheckout("2024-03-15");
booking.setBookingdates(bookingdates);
booking.setAdditionalneeds("Dinner");
gson = new Gson();
return gson.toJson(booking);
}
// Auth payload
public String setAuthPayload() {
Auth auth = new Auth();
auth.setUsername("admin");
auth.setPassword("password123");
gson = new Gson();
return gson.toJson(auth);
}
// --- Deserialization: JSON String → Java Object ---
public BookingResponse bookingResponseJava(String responseString) {
gson = new Gson();
return gson.fromJson(responseString, BookingResponse.class);
}
public String getTokenFromJSON(String tokenResponse) {
gson = new Gson();
TokenResponse response = gson.fromJson(tokenResponse, TokenResponse.class);
return response.getToken();
}
}
package com.thetestingacademy.base;
import com.thetestingacademy.asserts.AssertActions;
import com.thetestingacademy.endpoints.APIConstants;
import com.thetestingacademy.modules.PayloadManager;
import io.restassured.RestAssured;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.http.ContentType;
import io.restassured.path.json.JsonPath;
import io.restassured.response.Response;
import io.restassured.response.ValidatableResponse;
import io.restassured.specification.RequestSpecification;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.AfterTest;
public class BaseTest {
public RequestSpecification requestSpecification;
public AssertActions assertActions;
public PayloadManager payloadManager;
public JsonPath jsonPath;
public Response response;
public ValidatableResponse validatableResponse;
@BeforeTest
public void setUp() {
payloadManager = new PayloadManager();
assertActions = new AssertActions();
requestSpecification = new RequestSpecBuilder()
.setBaseUri(APIConstants.BASE_URL)
.addHeader("Content-Type", "application/json")
.build().log().all();
}
public String getToken() {
requestSpecification = RestAssured.given();
requestSpecification.baseUri(APIConstants.BASE_URL)
.basePath(APIConstants.AUTH_URL);
String payload = payloadManager.setAuthPayload();
response = requestSpecification.contentType(ContentType.JSON)
.body(payload).when().post();
return payloadManager.getTokenFromJSON(response.asString());
}
@AfterTest
public void tearDown() {
System.out.println("Finished the Test!");
}
}
package com.thetestingacademy.asserts;
import io.restassured.response.Response;
import static org.assertj.core.api.Assertions.assertThat;
import static org.testng.Assert.assertEquals;
public class AssertActions {
public void verifyResponseBody(String actual, String expected, String description) {
assertEquals(actual, expected, description);
}
public void verifyResponseBody(int actual, int expected, String description) {
assertEquals(actual, expected, description);
}
public void verifyStatusCode(Response response, Integer expected) {
assertEquals(response.getStatusCode(), (int) expected);
}
public void verifyStringKey(String keyExpect, String keyActual) {
assertThat(keyExpect).isNotNull();
assertThat(keyExpect).isNotBlank();
assertThat(keyExpect).isEqualTo(keyActual);
}
public void verifyStringKeyNotNull(Integer keyExpect) {
assertThat(keyExpect).isNotNull();
}
public void verifyStringKeyNotNull(String keyExpect) {
assertThat(keyExpect).isNotNull();
}
public void verifyResponseTime(Response response, long maxMillis) {
assertThat(response.getTime()).isLessThan(maxMillis);
}
public void verifyContentType(Response response, String expectedContentType) {
assertThat(response.getContentType()).contains(expectedContentType);
}
}
package com.thetestingacademy.tests.crud;
import com.thetestingacademy.base.BaseTest;
import com.thetestingacademy.endpoints.APIConstants;
import io.restassured.RestAssured;
import org.testng.annotations.Test;
public class TestHealthCheck extends BaseTest {
@Test(groups = "reg", priority = 1)
public void testHealthCheckGET() {
requestSpecification.basePath(APIConstants.PING_URL);
response = RestAssured.given(requestSpecification)
.when()
.get();
validatableResponse = response.then().log().all();
validatableResponse.statusCode(201);
}
}
package com.thetestingacademy.tests.crud;
import com.thetestingacademy.base.BaseTest;
import com.thetestingacademy.endpoints.APIConstants;
import io.qameta.allure.Description;
import io.qameta.allure.Owner;
import io.restassured.RestAssured;
import org.testng.annotations.Test;
public class TestCreateToken extends BaseTest {
@Test(groups = "reg", priority = 1)
@Owner("Promode")
@Description("TC#2 - Create Token and Verify")
public void testTokenPOST() {
requestSpecification.basePath(APIConstants.AUTH_URL);
response = RestAssured.given(requestSpecification)
.when()
.body(payloadManager.setAuthPayload())
.post();
validatableResponse = response.then().log().all();
validatableResponse.statusCode(200);
String token = payloadManager.getTokenFromJSON(response.asString());
assertActions.verifyStringKeyNotNull(token);
}
}
package com.thetestingacademy.tests.crud;
import com.thetestingacademy.base.BaseTest;
import com.thetestingacademy.endpoints.APIConstants;
import com.thetestingacademy.pojos.reponse.BookingResponse;
import io.qameta.allure.Description;
import io.qameta.allure.Owner;
import io.restassured.RestAssured;
import org.testng.annotations.Test;
public class TestCreateBooking extends BaseTest {
@Test(groups = "reg", priority = 1)
@Owner("Promode")
@Description("TC#1 - Verify that the Booking can be Created")
public void testCreateBookingPOST_Positive() {
requestSpecification.basePath(APIConstants.CREATE_UPDATE_BOOKING_URL);
response = RestAssured.given(requestSpecification)
.when()
.body(payloadManager.createPayloadBookingAsString())
.log().all()
.post();
validatableResponse = response.then().log().all();
validatableResponse.statusCode(200);
BookingResponse bookingResponse = payloadManager.bookingResponseJava(response.asString());
assertActions.verifyStringKeyNotNull(bookingResponse.getBookingid());
assertActions.verifyStringKey(bookingResponse.getBooking().getFirstname(), "Pramod");
}
@Test(groups = "reg", priority = 2)
@Description("TC#2 - Verify booking with empty payload returns error")
public void testCreateBookingPOST_Negative_EmptyBody() {
requestSpecification.basePath(APIConstants.CREATE_UPDATE_BOOKING_URL);
response = RestAssured.given(requestSpecification)
.when()
.body("")
.post();
validatableResponse = response.then().log().all();
validatableResponse.statusCode(500);
}
@Test(groups = "reg", priority = 3)
@Description("TC#3 - Verify booking with non-ASCII characters")
public void testCreateBookingPOST_EdgeCase_NonASCII() {
requestSpecification.basePath(APIConstants.CREATE_UPDATE_BOOKING_URL);
response = RestAssured.given(requestSpecification)
.when()
.body(payloadManager.createPayloadBookingAsStringWrongBody())
.post();
validatableResponse = response.then().log().all();
validatableResponse.statusCode(200);
BookingResponse bookingResponse = payloadManager.bookingResponseJava(response.asString());
assertActions.verifyStringKeyNotNull(bookingResponse.getBookingid());
}
@Test(groups = "qa", priority = 4)
@Description("TC#4 - Verify booking with random Faker data")
public void testCreateBookingPOST_FakerData() {
requestSpecification.basePath(APIConstants.CREATE_UPDATE_BOOKING_URL);
response = RestAssured.given(requestSpecification)
.when()
.body(payloadManager.createPayloadBookingFakerJS())
.post();
validatableResponse = response.then().log().all();
validatableResponse.statusCode(200);
BookingResponse bookingResponse = payloadManager.bookingResponseJava(response.asString());
assertActions.verifyStringKeyNotNull(bookingResponse.getBookingid());
assertActions.verifyStringKeyNotNull(bookingResponse.getBooking().getFirstname());
}
}
This pattern demonstrates a complete CRUD workflow where test methods share state via TestNG's ITestContext. Each step depends on the previous one.
package com.thetestingacademy.tests.e2e_integration;
import com.thetestingacademy.base.BaseTest;
import com.thetestingacademy.endpoints.APIConstants;
import com.thetestingacademy.pojos.reponse.BookingResponse;
import io.restassured.RestAssured;
import org.testng.ITestContext;
import org.testng.annotations.Test;
public class TestIntegrationFlow1 extends BaseTest {
// Step 1: Create a booking
@Test(priority = 1)
public void testCreateBooking(ITestContext iTestContext) {
requestSpecification.basePath(APIConstants.CREATE_UPDATE_BOOKING_URL);
response = RestAssured.given(requestSpecification)
.when()
.body(payloadManager.createPayloadBookingAsString())
.post();
validatableResponse = response.then().log().all();
validatableResponse.statusCode(200);
BookingResponse bookingResponse = payloadManager.bookingResponseJava(response.asString());
// Store booking ID for subsequent steps
iTestContext.setAttribute("bookingid", bookingResponse.getBookingid());
assertActions.verifyStringKeyNotNull(bookingResponse.getBookingid());
}
// Step 2: Verify the booking exists
@Test(priority = 2)
public void testVerifyBookingId(ITestContext iTestContext) {
Integer bookingid = (Integer) iTestContext.getAttribute("bookingid");
String basePathGET = APIConstants.CREATE_UPDATE_BOOKING_URL + "/" + bookingid;
requestSpecification.basePath(basePathGET);
response = RestAssured.given(requestSpecification)
.when()
.get();
validatableResponse = response.then().log().all();
validatableResponse.statusCode(200);
// Verify the returned booking matches what we created
BookingResponse bookingResponse = payloadManager.bookingResponseJava(response.asString());
assertActions.verifyStringKey(bookingResponse.getBooking().getFirstname(), "Pramod");
}
// Step 3: Update the booking (requires auth token)
@Test(priority = 3)
public void testUpdateBookingByID(ITestContext iTestContext) {
Integer bookingid = (Integer) iTestContext.getAttribute("bookingid");
String token = getToken();
// Store token for the delete step
iTestContext.setAttribute("token", token);
String basePathPUT = APIConstants.CREATE_UPDATE_BOOKING_URL + "/" + bookingid;
requestSpecification.basePath(basePathPUT);
response = RestAssured.given(requestSpecification)
.cookie("token", token)
.when()
.body(payloadManager.fullUpdatePayloadAsString())
.put();
validatableResponse = response.then().log().all();
validatableResponse.statusCode(200);
}
// Step 4: Verify the update
@Test(priority = 4)
public void testVerifyUpdatedBooking(ITestContext iTestContext) {
Integer bookingid = (Integer) iTestContext.getAttribute("bookingid");
String basePathGET = APIConstants.CREATE_UPDATE_BOOKING_URL + "/" + bookingid;
requestSpecification.basePath(basePathGET);
response = RestAssured.given(requestSpecification)
.when()
.get();
validatableResponse = response.then().log().all();
validatableResponse.statusCode(200);
BookingResponse bookingResponse = payloadManager.bookingResponseJava(response.asString());
assertActions.verifyStringKey(bookingResponse.getBooking().getFirstname(), "UpdatedFirstName");
}
// Step 5: Delete the booking
@Test(priority = 5)
public void testDeleteBookingById(ITestContext iTestContext) {
Integer bookingid = (Integer) iTestContext.getAttribute("bookingid");
String token = (String) iTestContext.getAttribute("token");
String basePathDELETE = APIConstants.CREATE_UPDATE_BOOKING_URL + "/" + bookingid;
requestSpecification.basePath(basePathDELETE);
response = RestAssured.given().spec(requestSpecification)
.cookie("token", token)
.when()
.delete();
validatableResponse = response.then().log().all();
validatableResponse.statusCode(201);
}
}
// Token-based authentication flow:
// 1. Generate token via /auth endpoint
public String getToken() {
requestSpecification = RestAssured.given();
requestSpecification.baseUri(APIConstants.BASE_URL)
.basePath(APIConstants.AUTH_URL);
String payload = payloadManager.setAuthPayload();
response = requestSpecification.contentType(ContentType.JSON)
.body(payload).when().post();
return payloadManager.getTokenFromJSON(response.asString());
}
// 2. Use token as cookie in protected requests
String token = getToken();
response = RestAssured.given(requestSpecification)
.cookie("token", token)
.when()
.body(payloadManager.fullUpdatePayloadAsString())
.put();
// 3. Bearer token alternative
response = RestAssured.given(requestSpecification)
.header("Authorization", "Bearer " + token)
.when()
.get();
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="API Test Suite">
<test verbose="2" preserve-order="true" name="CRUD Tests">
<classes>
<class name="com.thetestingacademy.tests.crud.TestHealthCheck"/>
<class name="com.thetestingacademy.tests.crud.TestCreateToken"/>
<class name="com.thetestingacademy.tests.crud.TestCreateBooking"/>
</classes>
</test>
</suite>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="E2E Integration Suite">
<test verbose="2" preserve-order="true" name="Integration Flow 1">
<classes>
<class name="com.thetestingacademy.tests.e2e_integration.TestIntegrationFlow1"/>
</classes>
</test>
</suite>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Parallel API Suite" parallel="methods" thread-count="3">
<test verbose="2" name="Regression">
<groups>
<run>
<include name="reg"/>
</run>
</groups>
<classes>
<class name="com.thetestingacademy.tests.crud.TestHealthCheck"/>
<class name="com.thetestingacademy.tests.crud.TestCreateToken"/>
<class name="com.thetestingacademy.tests.crud.TestCreateBooking"/>
</classes>
</test>
</suite>
import io.qameta.allure.*;
@Test(groups = "reg", priority = 1)
@TmsLink("https://bugz.atlassian.net/browse/TS-1")
@Owner("Promode")
@Description("TC#1 - Verify that the Booking can be Created")
@Severity(SeverityLevel.CRITICAL)
@Story("Booking CRUD")
@Feature("Booking API")
public void testCreateBookingPOST() {
Allure.step("Set base path to booking endpoint");
requestSpecification.basePath(APIConstants.CREATE_UPDATE_BOOKING_URL);
Allure.step("Send POST request with booking payload");
response = RestAssured.given(requestSpecification)
.when()
.body(payloadManager.createPayloadBookingAsString())
.post();
Allure.step("Verify response status code is 200");
validatableResponse = response.then().statusCode(200);
Allure.step("Verify booking ID is not null");
BookingResponse bookingResponse = payloadManager.bookingResponseJava(response.asString());
assertActions.verifyStringKeyNotNull(bookingResponse.getBookingid());
Allure.addAttachment("Response Body", "application/json", response.asString(), "json");
}
# Run tests with specific suite
mvn clean test -DsuiteXmlFile=testng_e2e.xml
# Generate Allure report
allure generate target/allure-results --clean -o allure-report
allure open allure-report
// Extract single value with JsonPath
String firstname = response.jsonPath().getString("booking.firstname");
Integer bookingId = response.jsonPath().getInt("bookingid");
List<Integer> allIds = response.jsonPath().getList(".", Integer.class);
// Extract as POJO with GSON
BookingResponse bookingResponse = payloadManager.bookingResponseJava(response.asString());
// Extract with ValidatableResponse
validatableResponse = response.then()
.body("booking.firstname", equalTo("Pramod"))
.body("booking.totalprice", greaterThan(0))
.body("bookingid", notNullValue());
// Chain extraction
String token = response.then()
.statusCode(200)
.extract()
.path("token");
import static io.restassured.module.jsv.JsonSchemaValidator.matchesJsonSchemaInClasspath;
@Test
public void testBookingResponseMatchesSchema() {
response = RestAssured.given(requestSpecification)
.basePath(APIConstants.CREATE_UPDATE_BOOKING_URL)
.when()
.body(payloadManager.createPayloadBookingAsString())
.post();
response.then()
.statusCode(200)
.body(matchesJsonSchemaInClasspath("schemas/booking-response-schema.json"));
}
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": ["bookingid", "booking"],
"properties": {
"bookingid": { "type": "integer" },
"booking": {
"type": "object",
"required": ["firstname", "lastname", "totalprice", "depositpaid", "bookingdates"],
"properties": {
"firstname": { "type": "string" },
"lastname": { "type": "string" },
"totalprice": { "type": "integer" },
"depositpaid": { "type": "boolean" },
"bookingdates": {
"type": "object",
"required": ["checkin", "checkout"],
"properties": {
"checkin": { "type": "string" },
"checkout": { "type": "string" }
}
},
"additionalneeds": { "type": "string" }
}
}
}
}
iTestContext.setAttribute() to share booking IDs and tokens across test methods.reg, qa, smoke) and set priorities for ordered execution in integration flows..log().all() on both request and response for easy debugging when tests fail.assertActions.verifyResponseTime().- name: Install QA Skills
run: npx @qaskills/cli add restassured-api-framework10 of 29 agents supported