Back to Courses
REST ASSURED WITH JAVA — BUILD A REAL AUTOMATION FRAMEWORK

API Automation Testing with REST Assured

Write automated tests for real web APIs using Java. Learn what the tools do, why they exist, and how to combine them into a framework that runs in any CI/CD pipeline.

25+
Days of Training
14
Modules
100+
Topics Covered
Live
Framework

Who Is This Course For?

This course is for manual testers and junior Java developers who want to build a production-grade API test automation framework. You will learn every tool by name and command — and you will also understand exactly why each tool exists so you can adapt to any project on day one of a new job.

REST Assured Java + TestNG GitHub API (Live) Jackson / POJO Maven + Surefire Framework Design

Your Learning Roadmap

01
REST Assured Setup & BDD Syntax
02
Validation, JSON Path & Auth
03
POJO, TestNG & BaseClass
04
Properties, Helpers & Maven
05
Complete Framework — Job Ready
Course Modules
1
Introduction to REST Assured & Project Setup
Why this module matters: Before you can write a single test, you need a project that compiles and runs. Getting Maven and your dependencies right here means every other module builds on solid ground — a bad setup wastes hours later.
Maven Project Setup
  • Creating a Maven project in Eclipse — understanding pom.xml structure
  • Adding core dependencies: io.rest-assured:rest-assured, org.testng:testng, com.fasterxml.jackson.core:jackson-databind
  • Dependency scopes: why REST Assured uses test scope
  • Running mvn dependency:resolve to confirm setup
HTTP Protocol Fundamentals
  • HTTP methods: GET (read), POST (create), PUT (replace), PATCH (partial update), DELETE (remove)
  • Request anatomy: URL, headers, body, query params, path params
  • Response anatomy: status code, response headers, JSON body
  • Status code groups — 2xx success, 4xx client errors, 5xx server errors
2
REST Assured BDD Syntax — given / when / then
Why this module matters: The given/when/then pattern is not just REST Assured syntax — it is the industry standard for readable test automation. Every senior engineer on a code review will immediately understand a test written this way, which makes collaboration and maintenance much easier.
The BDD Chain
  • given() — builds the request: headers, body, params. Think of it as "given these conditions..."
  • when() — fires the HTTP call: .get(url), .post(url), .put(url), .delete(url)
  • then() — asserts the response: "...then I expect this result"
  • Full readable chain: given().when().get("/repos").then().statusCode(200)
Syntactic Sugar — Readability Aliases
  • .and() — reads naturally between assertions; no functional difference
  • .assertThat() — alternative to then(), used by teams preferring assertion-first style
  • Why REST Assured offers these aliases: tests should read like sentences, not code
Key Return Types
  • RequestSpecification — what given() returns; you build the request on it
  • Response — raw HTTP response object returned by when().get()
  • ValidatableResponse — what then() returns; enables chained assertion methods
3
Response Validation — Status Codes, Headers & Body
Why this module matters: An API that returns the wrong status code, wrong content type, or wrong data is a broken API — even if no exception was thrown. Learning to check all three layers of a response is what separates a thorough tester from someone who only checks "did it not crash?"
Status Code Assertions
  • .statusCode(200) — assert exact success code for GET/PUT responses
  • .statusCode(201) — assert "created" for POST; .statusCode(204) for DELETE (no body returned)
  • .statusCode(anyOf(is(200), is(201))) — when multiple codes are valid
Header & Body Validation with Hamcrest
  • .header("Content-Type", containsString("json")) — confirm JSON response type
  • .body("name", equalTo("myrepo")) — check a single field value inline
  • .body("items.name", hasItems("repo1","repo2")) — verify list contents
  • notNullValue(), greaterThan(0), containsString() — Hamcrest matchers toolkit
  • Chaining multiple .body() calls in one then() block — assert everything at once
4
JSON Path Extraction — Reading Values from the Response
Why this module matters: Inline body assertions are fine for simple checks, but real tests need to read a value from one response and use it in the next request. JSON Path extraction is how you chain API calls together — create a resource, capture its ID, then use that ID to fetch or delete it.
Extracting the Response Object
  • .extract().jsonPath() — returns a JsonPath object for field-level data extraction
  • .extract().asString() — the raw JSON string if you need to inspect or log it
  • When to extract vs. when to assert inline — a practical decision guide
JsonPath Methods
  • jsonPath.get("name") — single value extraction (auto-typed by Jackson)
  • jsonPath.getString("login") / getInt("id") / getFloat("size") — explicit typed extraction
  • jsonPath.getList("repos") — entire array as a Java List
  • jsonPath.getList("repos", String.class) — typed list
  • jsonPath.getJsonObject("owner") — nested object as a Map
  • jsonPath.getList("repos").size() — count how many items came back
Nested Paths & Chained Tests
  • Dot notation for nested data: jsonPath.get("owner.login")
  • Array indexing: jsonPath.get("repos[0].name")
  • Storing extracted IDs or names to reuse in the next API call
5
Building Requests — Parameters, Headers & Payload
Why this module matters: Most real APIs require more than just a URL. Learning to attach path params, query params, headers, and a body is what enables you to test every single endpoint a server exposes — not just the simple "get everything" ones.
Path & Query Parameters
  • .pathParam("owner","octocat") used with URL template /repos/{owner}/{repo}
  • .queryParam("page", 2) and .queryParam("per_page", 30) — pagination control
  • Chaining multiple .queryParam() calls vs. passing a Map via .queryParams(map)
Request Headers & Body
  • .contentType(ContentType.JSON) — tells the server you are sending JSON
  • .accept(ContentType.JSON) — tells the server what format you want back
  • .header("Accept", "application/vnd.github.v3+json") — GitHub-specific version header
  • .body("{\"name\":\"myrepo\"}") — raw JSON string body for quick tests
  • .body(pojoObject) — POJO auto-serialised by Jackson; cleaner and type-safe
  • PUT vs PATCH difference: PUT replaces the full resource; PATCH updates only specified fields
6
Authentication — Proving Your Identity to the API
Why this module matters: Almost every production API is protected. If you can only test public, unauthenticated endpoints you are testing less than 10% of a real system. This module unlocks the ability to automate tests for everything behind a login.
Bearer Token Auth (GitHub)
  • .header("Authorization", "Bearer " + token) — the standard pattern for token-based auth
  • Generating a GitHub Personal Access Token (PAT) from GitHub Settings → Developer Settings
  • Required scopes for our tests: repo, delete_repo, admin:org
  • Why you store the token in a variable now and move it to a properties file later in the course
Negative Auth Tests
  • Test with no token — expect 401 Unauthorized (not recognised)
  • Test with a valid token but insufficient scope — expect 403 Forbidden (recognised but not allowed)
  • Why testing both failure modes matters: they reveal different security gaps
7
GitHub API as the Live Test Application
Why this module matters: Testing against a real, live API (not a mocked server) gives you the experience that interviewers actually test for. GitHub's API is free, well-documented, and has complex enough endpoints to exercise every skill in this course.
GitHub API Basics
  • Base URL: https://api.github.com — set once in BaseClass, used everywhere
  • GitHub API version header: X-GitHub-Api-Version: 2022-11-28
  • Rate limits: 5000 requests/hour with a token — how to stay within limits during testing
Repository CRUD End-to-End
  • Create: POST /user/repos — returns 201 with full repo object
  • Read: GET /repos/{owner}/{repo} — extract and assert name, visibility, owner
  • Update: PATCH /repos/{owner}/{repo} — change name or description, assert the change
  • Delete: DELETE /repos/{owner}/{repo} — expect 204 No Content; verify deletion with a follow-up GET that returns 404
  • Complete E2E scenario: create → read → update → delete as four chained test methods
8
POJO Serialization & Deserialization with Jackson
Why this module matters: Typing raw JSON strings into tests is error-prone and hard to maintain. POJOs turn your request body into a Java object with proper types — no more missing quotes or typos in field names. And when you deserialise responses into POJOs, your assertions become clean Java property checks instead of string path lookups.
POJO Design
  • POJO = a plain Java class whose fields mirror the JSON structure of a request or response
  • Private fields + public getters/setters + no-argument constructor — the three requirements
  • Request POJO (what you send) vs Response POJO (what you receive) as separate classes
Jackson Annotations
  • @JsonProperty("html_url") — maps the JSON key name to your Java field name when they differ
  • @JsonIgnoreProperties(ignoreUnknown = true) — prevents failure when the API adds new fields you didn't model
  • @JsonInclude(Include.NON_NULL) — skip null fields when serialising, keeping the request body clean
Serialization & Deserialization in Tests
  • Serialisation: .body(repoPojo) — REST Assured + Jackson converts the POJO to JSON automatically
  • Deserialisation: .extract().as(RepoResponse.class) — JSON response mapped to a typed Java object
  • Asserting on POJO fields: Assert.assertEquals(repo.getName(), "myrepo") — clean, IDE-autocompleted assertions
9
TestNG Integration — Annotation Lifecycle & XML Suite
Why this module matters: Without a test runner managing the lifecycle, every test has to set up the whole world from scratch and tear it down at the end — which is slow and fragile. TestNG annotations let you separate the "one-time connection setup" from the "per-test cleanup", which is the difference between a 10-second suite and a 10-minute one.
Annotation Lifecycle
  • @BeforeClass — runs once before all tests in this file (used for: set base URI, read config, auth setup)
  • @AfterClass — runs once after all tests finish (used for: final cleanup, teardown resources)
  • @BeforeMethod — runs before every single test method (used for: creating fresh test data)
  • @AfterMethod — runs after every single test (used for: logging pass/fail, deleting test data)
ITestResult — Knowing What Happened
  • @AfterMethod public void tearDown(ITestResult result) — TestNG injects the result object automatically
  • result.getStatus() — returns ITestResult.SUCCESS, FAILURE, or SKIP
  • result.getName() — which test method just ran, for log messages
  • Why this matters: you can log "PASSED: createRepo" or "FAILED: deleteRepo" without extra assertions
testng.xml — One File to Rule Them All
  • XML suite defines which classes and groups run — no need to run files individually
  • Groups: <include name="smoke"/> runs only the fast checks; <include name="regression"/> runs everything
  • Parallel execution: parallel="methods" to speed up long suites
10
Framework Design — BaseClass & Inheritance Pattern
Why this module matters: The moment you have more than two test files, you have a choice: copy the setup code into each file, or inherit it from one shared parent. Every professional framework uses inheritance. This module teaches the exact pattern you will be asked to explain in every senior QA interview.
BaseClass Design
  • public class BaseClass — the shared parent that holds everything all tests need
  • RestAssured.baseURI = "https://api.github.com" in @BeforeClass — set once, used by all
  • protected static String TOKEN — loaded from properties file, available to all child classes
  • Why static: token does not change during the suite run, so one copy is enough
Inheritance in Practice
  • public class RepoTests extends BaseClass — inherits all setup automatically
  • public class OrgTests extends BaseClass — same pattern, different test scope
  • No need to declare base URI or token in any test class — it just works
Package Structure
  • com.training.base → BaseClass | com.training.tests → all test classes
  • com.training.pojo → data objects | com.training.utils → helpers
  • src/test/resources → testng.xml, properties files
11
Logging & Response Specification Builder
Why this module matters: When a test fails in CI at 2am, the logs are your only window into what went wrong. Smart logging — especially logging only on failure — means you get exactly the data you need without drowning in noise. The ResponseSpecBuilder means you write the "must return 200 JSON" rule once, not 200 times.
REST Assured Logging
  • .log().all() — full request detail (URL, headers, body) printed to console
  • .log().ifValidationFails() — only logs when an assertion fails; keeps CI output clean
  • RestAssured.enableLoggingOfRequestAndResponseIfValidationFails() — enables this globally in one line
ResponseSpecBuilder — Reusable Assertions
  • ResponseSpecBuilder — define a reusable set of response checks (status + content type)
  • builder.expectStatusCode(200).expectContentType(ContentType.JSON)
  • ResponseSpecification spec = builder.build()
  • Apply per test: then().spec(spec) — or globally: RestAssured.responseSpecification = spec
  • Why this matters: change the expected status code in one place and every test that uses the spec updates automatically
12
Properties Files & Environment Management
Why this module matters: A framework that only works against one hardcoded URL is not a real framework — it is a script. Properties files are how professional teams make the same test suite point at dev, QA, or production just by passing a flag. This is one of the most-asked topics in automation engineer interviews.
Properties File Format
  • Simple key=value text files: base.url=https://api.github.com
  • Three environment files: dev.properties, qa.properties, prod.properties
  • Stored in src/test/resources/ so Maven includes them automatically
Reading Properties in Java
  • Properties props = new Properties() — create a container
  • props.load(new FileInputStream("src/test/resources/qa.properties")) — load the file
  • props.getProperty("base.url") — read any value by key
  • Done in BaseClass @BeforeClass so all child test classes get the value automatically
Environment Switching
  • System.getProperty("env") reads the environment flag passed at runtime
  • Command: mvn test -Denv=qa — no code change required
  • Conditional loading: read the env value first, then load the matching properties file
13
API Helper Utilities & Generics
Why this module matters: Every test that sends a GET request repeats the same chain of given/when/get/extract/as. Moving that pattern into a helper method means each test becomes one line. Generics let you write that method once and have it return any type — you are not writing a new helper for every POJO.
API Helper Class
  • public class ApiHelper — centralises repetitive request patterns into named methods
  • public Response get(String endpoint) — wraps the full given/header/when/get chain
  • public Response post(String endpoint, Object body) — wraps POST with content type and body
  • Test method goes from 6 lines to 1 line per request
Generic Methods
  • <T> — the Java generic type parameter, meaning "this method works with any type you tell it"
  • public <T> T getAs(String endpoint, Class<T> type) — one method that returns any POJO
  • Calling it: RepoResponse repo = helper.getAs("/repos/me/test", RepoResponse.class)
  • Why this is powerful: add 10 new POJOs without writing 10 new helper methods
DRY in Framework Context
  • Don't Repeat Yourself — every pattern that appears in more than two places belongs in a utility
  • Helper vs. test class responsibility: helpers make calls; tests assert outcomes
  • How the complete picture looks: BaseClass → ApiHelper → TestClass → POJO
14
Complete Framework — Maven Execution & CI/CD Readiness
Why this module matters: A framework you can only run by clicking "Run" in your IDE is not useful to a team. Being able to trigger the full suite with one terminal command — and have a CI server do the same — is what makes your automation genuinely valuable to the organisation you join.
Maven Surefire Plugin
  • maven-surefire-plugin — the bridge between Maven and TestNG; it reads your testng.xml and runs the suite
  • Config in pom.xml: <suiteXmlFiles><suiteXmlFile>testng.xml</suiteXmlFile>
  • Command: mvn test — runs the full suite; mvn test -Denv=qa — runs against QA
  • Pinning plugin version: avoids unexpected test failures after Maven updates
End-to-End Execution Flow
  • Maven reads pom.xml → Surefire reads testng.xml → TestNG instantiates test classes → BaseClass @BeforeClass loads properties → REST Assured fires HTTP calls → results reported
  • HTML reports auto-generated in target/surefire-reports/ — shareable with the team
CI/CD Integration
  • Jenkins or GitHub Actions pipeline: add mvn test -Denv=qa as a build step
  • Environment variables in CI replace local properties file values — no secrets in code
  • Full framework folder review: base/, tests/, pojo/, utils/, resources/
  • Walking through the complete project in a mock interview — how to present this framework confidently
Interview Preparation

REST Assured Core Q&A

Walk through given().when().then(). Why use ResponseSpecBuilder? What is the difference between inline .body() assertion and .extract().jsonPath().get()? When would you choose each?

Framework Architecture Q&A

Why is RestAssured.baseURI set in @BeforeClass of BaseClass? How does inheritance eliminate repeated setup? What role does ITestResult play in @AfterMethod?

POJO & Environment Q&A

Explain @JsonIgnoreProperties(ignoreUnknown=true) in plain English. How do you make the same test suite run against dev and QA without changing code? How does System.getProperty() fit in?

Maven & CI Q&A

How does mvn test know which tests to run? What connects pom.xml to testng.xml? How would you configure a CI pipeline to run your suite automatically after every code push?