Test Frameworks
REST Assured
Core Rest Assured syntax, request/response specs, JSON path validation, POJO serialization, authentication schemes, TestNG integration, Maven setup, and coding scenarios — with rapid-fire Q&A.
01Core Rest Assured syntax
What is Rest Assured and why use it over other approaches?
Rest Assured is an open-source Java DSL for testing REST APIs. It removes the boilerplate of using raw HTTP clients (HttpClient, HttpURLConnection) by giving a fluent, readable given-when-then BDD syntax, built-in JSON/XML parsing (JsonPath, XmlPath), and Hamcrest matcher integration for assertions.
- Readable, close to plain English — good for reviews and non-Java stakeholders.
- First-class JSON/XML response parsing and schema validation.
- Plays well with TestNG/JUnit, Maven/Gradle, and CI pipelines.
Explain the given / when / then structure.
- given() — the arrange block: set up the request (headers, params, body, auth, base URI).
- when() — the act block: the HTTP action (get, post, put, delete).
- then() — the assert block: validate status code, headers, and body.
given()
.baseUri("https://api.example.com")
.header("Content-Type", "application/json")
.queryParam("page", 2)
.when()
.get("/users")
.then()
.statusCode(200)
.body("data.size()", equalTo(6));
given() for a bare GET — when().get(url).then()... is valid. Interviewers like to hear you know the BDD block is optional sugar.How do you send path params, query params, and headers?
given()
.pathParam("userId", 15)
.queryParam("active", true)
.header("Authorization", "Bearer " + token)
.headers("Accept", "application/json", "X-Trace", id)
.when()
.get("/users/{userId}")
.then()
.statusCode(200);
pathParam substitutes {userId} in the URL; queryParam appends ?active=true. Use params() for form/query pairs and formParam() for application/x-www-form-urlencoded bodies.
How do you send a POST with a JSON body?
// 1) As a raw string
given()
.contentType(ContentType.JSON)
.body("{ \"name\": \"morpheus\", \"job\": \"leader\" }")
.when()
.post("/users")
.then()
.statusCode(201)
.body("name", equalTo("morpheus"));
// 2) As a Map (auto-serialized to JSON)
Map<String,Object> payload = new HashMap<>();
payload.put("name", "morpheus");
payload.put("job", "leader");
given().contentType(ContentType.JSON).body(payload)
.when().post("/users").then().statusCode(201);02Request & Response Specifications
What are RequestSpecification and ResponseSpecification, and why use them?
They let you define reusable request/response setup once and apply it across many tests — eliminating duplication of base URI, common headers, auth, and repeated assertions (like status 200 + JSON content type). Great for keeping a framework DRY.
RequestSpecification reqSpec = new RequestSpecBuilder()
.setBaseUri("https://api.example.com")
.setContentType(ContentType.JSON)
.addHeader("Authorization", "Bearer " + token)
.build();
ResponseSpecification resSpec = new ResponseSpecBuilder()
.expectStatusCode(200)
.expectContentType(ContentType.JSON)
.expectResponseTime(lessThan(2000L))
.build();
given().spec(reqSpec)
.when().get("/users/2")
.then().spec(resSpec)
.body("data.id", equalTo(2));
What are the static config options (RestAssured.baseURI, filters, etc.)?
RestAssured.baseURI,basePath,port— global defaults for all requests.RestAssured.requestSpecification/responseSpecification— global specs.RestAssured.filters(...)— attach logging or custom filters globally.RestAssured.reset()— reset all static state (call in@AfterMethod/@AfterClassto avoid test bleed).
03Validation & JSON path
How does Rest Assured validate response bodies? What is Hamcrest's role?
The .body(jsonPath, matcher) method takes a GPath/JsonPath expression and a Hamcrest matcher. Rest Assured evaluates the path against the parsed body and asserts it against the matcher.
import static org.hamcrest.Matchers.*;
.then()
.body("data.email", equalTo("janet.weaver@reqres.in"))
.body("data.id", greaterThan(0))
.body("data", hasKey("first_name"))
.body("support.url", containsString("reqres"))
.body("data.first_name", notNullValue());
How do you assert on arrays / collections?
// JSON: { "data": [ {"id":7,...}, {"id":8,...} ] }
.then()
.body("data.size()", equalTo(6))
.body("data.id", hasItems(7, 8))
.body("data.first_name", everyItem(notNullValue()))
.body("data.findAll { it.id > 8 }.size()", equalTo(4))
.body("data[0].email", endsWith("@reqres.in"));
Rest Assured uses Groovy's GPath, so you can use findAll, find, collect, it.field, max, min, sum inside path expressions.
How do you do JSON schema validation?
Add the json-schema-validator module, then match against a schema file on the classpath.
import static io.restassured.module.jsv.JsonSchemaValidator.matchesJsonSchemaInClasspath;
.then()
.assertThat()
.body(matchesJsonSchemaInClasspath("schemas/user-schema.json"));
04Serialization, Deserialization & POJOs
What is serialization/deserialization in Rest Assured, and how does it work?
Serialization = converting a Java object (POJO) into a JSON/XML request body. Deserialization = converting a response body back into a Java object. Rest Assured delegates this to Jackson or Gson if they're on the classpath — it auto-detects.
// POJO
public class User {
private String name;
private String job;
// getters + setters (Jackson needs them)
}
// Serialization: POJO -> JSON request
User u = new User();
u.setName("morpheus"); u.setJob("leader");
// Deserialization: JSON response -> POJO
User created = given().contentType(ContentType.JSON).body(u)
.when().post("/users")
.then().statusCode(201)
.extract().as(User.class);
assertEquals(created.getName(), "morpheus");
05Authentication & Security
What authentication schemes does Rest Assured support?
| Scheme | Syntax |
|---|---|
| Basic (preemptive) | given().auth().preemptive().basic("user","pass") |
| Basic (challenged) | given().auth().basic("user","pass") |
| Digest | given().auth().digest("user","pass") |
| OAuth 1.0 | given().auth().oauth(consumerKey, consumerSecret, token, secret) |
| OAuth 2.0 / Bearer | given().auth().oauth2(accessToken) |
| API key / custom | given().header("x-api-key", key) |
Explain preemptive vs challenged basic auth.
- Challenged (default basic): the client first sends without credentials, gets a
401 WWW-Authenticate, then resends with the header. Two round trips. - Preemptive: the
Authorization: Basic ...header is sent on the first request. One round trip. Most modern APIs expect this.
.basic() against an API that doesn't return a proper 401 challenge, auth silently fails — that's a common real-world bug, and preemptive fixes it.Walk through testing an OAuth2 / token-based flow end to end.
The realistic pattern: hit the auth/login endpoint, extract the token, then use it as a bearer token on subsequent calls.
// 1) Get token
String token = given()
.contentType(ContentType.JSON)
.body("{ \"email\":\"eve.holt@reqres.in\", \"password\":\"pistol\" }")
.when()
.post("/login")
.then()
.statusCode(200)
.extract().path("token");
// 2) Use token on protected resource
given()
.auth().oauth2(token) // or .header("Authorization","Bearer "+token)
.when()
.get("/protected/resource")
.then()
.statusCode(200);
In a framework you'd wrap step 1 in a reusable getAuthToken() method, cache it, and inject it via a RequestSpecification.
How do you handle SSL / self-signed certificates?
// Relax HTTPS validation (test/staging with self-signed certs)
given().relaxedHTTPSValidation()
.when().get("/secure").then().statusCode(200);
// Or globally
RestAssured.useRelaxedHTTPSValidation();
.trustStore(...) / .keyStore(...).06Framework, TestNG & Maven
How would you structure a production Rest Assured framework?
- src/test/java — tests grouped by resource/endpoint.
- base/ — a BaseTest with common setup (base URI, specs, token).
- pojos/ or models/ — request/response POJOs.
- utils/ — helpers (config reader, token manager, data generators).
- endpoints/ or services/ — a "service layer" that wraps API calls into reusable methods (like a Page Object equivalent for APIs).
- src/test/resources — config.properties, schemas, test data (JSON/Excel), testng.xml, log4j2.xml.
- reporting — Allure or ExtentReports.
Which TestNG annotations matter and in what order do they run?
Order: @BeforeSuite → @BeforeTest → @BeforeClass → @BeforeMethod → @Test → @AfterMethod → @AfterClass → @AfterTest → @AfterSuite.
@BeforeClass— set up base URI, fetch auth token once per class.@BeforeMethod— reset per-test state.@Test(priority=, groups=, dependsOnMethods=, dataProvider=).@AfterClass— cleanup created test data.
How do you do data-driven testing?
@DataProvider(name = "users")
public Object[][] users() {
return new Object[][] {
{ "morpheus", "leader" },
{ "neo", "the one" }
};
}
@Test(dataProvider = "users")
public void createUser(String name, String job) {
given().contentType(ContentType.JSON)
.body(Map.of("name", name, "job", job))
.when().post("/users")
.then().statusCode(201).body("name", equalTo(name));
}
For external data, feed the DataProvider from Excel (Apache POI), CSV, or a JSON file.
How do you run tests in parallel and why is thread-safety a concern?
In testng.xml set parallel="methods" (or classes/tests) and thread-count. The risk: Rest Assured's static config (RestAssured.baseURI, global specs) and any shared mutable state (a static token variable) can be clobbered across threads.
<suite name="API" parallel="methods" thread-count="4">
<test name="UserTests">
<classes><class name="tests.UserTests"/></classes>
</test>
</suite>
Fixes: use local RequestSpecifications instead of static state, or ThreadLocal for shared objects.
What does the Maven side look like? Key dependencies & plugins.
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>json-schema-validator</artifactId>
</dependency>
<!-- testng, jackson-databind, allure-testng ... -->
- maven-surefire-plugin — runs tests, points to
testng.xml. mvn clean testruns the suite; CI (Jenkins/GitHub Actions) invokes the same command.- Use Maven profiles to switch environments (dev/staging/prod) via
-Por-Denv=.
07Coding / live scenarios
Scenario: Write an end-to-end CRUD flow for a /users resource.
@Test
public void userCrudFlow() {
RestAssured.baseURI = "https://api.example.com";
// CREATE
int id = given().contentType(ContentType.JSON)
.body(Map.of("name", "neo", "job", "hero"))
.when().post("/users")
.then().statusCode(201)
.extract().path("id");
// READ
given().pathParam("id", id)
.when().get("/users/{id}")
.then().statusCode(200).body("name", equalTo("neo"));
// UPDATE
given().pathParam("id", id).contentType(ContentType.JSON)
.body(Map.of("job", "the one"))
.when().put("/users/{id}")
.then().statusCode(200).body("job", equalTo("the one"));
// DELETE
given().pathParam("id", id)
.when().delete("/users/{id}")
.then().statusCode(204);
}
Scenario: Chain requests — use a value from response 1 in request 2.
// Get first user's id, then fetch that user's details
int firstId = given().when().get("/users?page=1")
.then().statusCode(200)
.extract().path("data[0].id");
given().pathParam("id", firstId)
.when().get("/users/{id}")
.then().statusCode(200)
.body("data.id", equalTo(firstId));
Scenario: Validate a specific object inside a JSON array by a field value.
// Find the user whose email is X and assert their first_name
.then()
.body("data.find { it.email == 'janet.weaver@reqres.in' }.first_name",
equalTo("Janet"));
// Or extract into a list and assert with Java/streams
List<Map<String,?>> users = resp.jsonPath().getList("data");
long count = users.stream()
.filter(u -> ((Integer)u.get("id")) > 8).count();
assertEquals(count, 4);
Scenario: How do you assert response time and headers?
.then()
.time(lessThan(2000L)) // under 2s
.header("Content-Type", containsString("application/json"))
.header("X-Powered-By", notNullValue())
.cookie("session", notNullValue());08Rapid-Fire Q&A
Reveal each answer to self-check, then test yourself with the quiz.
What is Rest Assured and why use it over raw HTTP clients?
Rest Assured is an open-source Java DSL that removes HTTP client boilerplate by giving a fluent given-when-then BDD syntax, built-in JSON/XML parsing, and Hamcrest matcher integration.
What is the correct order of TestNG lifecycle annotations?
TestNG runs: @BeforeSuite → @BeforeTest → @BeforeClass → @BeforeMethod → @Test → @AfterMethod → @AfterClass → @AfterTest → @AfterSuite.
Which authentication method sends credentials on the FIRST request without waiting for a 401 challenge?
Preemptive auth sends the Authorization header on the first request — one round trip instead of two. Challenged auth waits for a 401 WWW-Authenticate response first.
PUT vs PATCH — which statement is correct?
PUT replaces the entire resource (idempotent, full payload); PATCH applies a partial update to specific fields only.
Which HTTP methods are idempotent?
Idempotent means the same request repeated produces the same server state. GET, PUT, DELETE, and HEAD are idempotent; POST is not.