Advanced API Testing
This is Part 1 of the REST Assured Practice Roadmap — the work a new API automation engineer does in their first two sprints. Sprint 0 is understanding the API and deciding what to automate; Sprint 1 is building the framework and a first smoke suite. Each part lists the exercises, then gives worked examples and starter code, using Fake Store API as the practice project.
Sprint 0 — Understand the API Before Automating
Most failed API automation projects skip this step and automate whatever is easiest. Spend the first sprint answering: what exists, what matters, and what should be automated first?
Exercises
- List every endpoint from the documentation (Swagger/OpenAPI, Postman collection or network calls).
- Group them by module — auth, products, users, carts, orders.
- Mark public vs secured endpoints and the auth each needs.
- Map dependencies — which calls need data from others (login → token → cart).
- Rank business criticality — what breaks revenue or trust if it fails?
- Pick smoke APIs — a handful of calls proving the system is alive.
- Pick regression APIs — everything that needs full coverage.
- Exclude what isn't ready — unstable, deprecated or third-party calls.
- Map UI actions to APIs — open DevTools → Network, click through the app, note each call.
- List API-only validations — rules the UI hides (limits, rounding, permissions).
- Record ownership — which team or service owns each API and its data.
- Write it down as a scope document and a coverage matrix.
Worked example: a coverage matrix for Fake Store
| Endpoint | Module | Auth | Depends on | Criticality | Smoke | Regression |
|---|---|---|---|---|---|---|
GET /products |
Products | Public | — | High | ✅ | ✅ |
GET /products/{id} |
Products | Public | — | High | ✅ | ✅ |
GET /products/category/{name} |
Products | Public | — | Medium | ✅ | |
POST /auth/login |
Auth | Public | A user | High | ✅ | ✅ |
POST /carts |
Carts | Token | Login, products | High | ✅ | ✅ |
PUT /carts/{id} |
Carts | Token | A cart | Medium | ✅ | |
DELETE /carts/{id} |
Carts | Token | A cart | Medium | ✅ |
The matrix answers the questions a lead will ask — what's covered, what's missing, what runs on every build — and becomes the checklist for later sprints. Plan the positive, negative and edge cases for each endpoint in the API Testing Scenario Lab.
Sprint 1 — Framework Setup
Exercises
- Create a Maven project for API tests.
- Define the folder structure.
- Add dependencies: REST Assured, TestNG, a JSON library, schema validation, logging.
- Externalise the base URI per environment.
- Create a
BaseTestwith a shared request specification. - Enable logging for failed requests only.
- Keep secrets out of code and Git.
- Run one test from the command line and from CI.
- Push to Git with a README describing how to run it.
1. Structure
fakestore-api-tests/
├── pom.xml
├── README.md
└── src/test/
├── java/com/fakestore/
│ ├── base/ BaseTest.java
│ ├── config/ ConfigReader.java
│ ├── services/ ProductService.java, AuthService.java, CartService.java
│ └── tests/ SmokeTest.java
└── resources/
├── config/qa.properties
├── schemas/product.json
└── testng.xml
2. pom.xml dependencies
<properties>
<maven.compiler.release>17</maven.compiler.release>
</properties>
<dependencies>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>6.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>json-schema-validator</artifactId>
<version>6.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.11.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.19.2</version>
<scope>test</scope>
</dependency>
</dependencies>
Versions: REST Assured 6.x needs Java 17+ and brings Groovy 5 and Hamcrest with it — don't add Groovy or JsonPath separately. On Java 8 or 11, use REST Assured 5.5.7 instead (and still don't add Groovy yourself; mixing Groovy versions causes class-loading errors). Always check Maven Central for the latest patch release. Jackson (for POJOs) is optional — REST Assured also supports Gson and, from 6.0, Jackson 3.
3. Configuration per environment
# src/test/resources/config/qa.properties
baseUri=https://fakestoreapi.com
apiUser=mor_2314
public final class ConfigReader {
private static final Properties PROPS = new Properties();
static {
String env = System.getProperty("env", "qa");
try (InputStream in =
ConfigReader.class.getResourceAsStream(
"/config/" + env + ".properties")) {
if (in == null) {
throw new IllegalStateException("No config for env: " + env);
}
PROPS.load(in);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public static String get(String key) {
return System.getProperty(
key,
PROPS.getProperty(key)
);
}
}
mvn test -Denv=staging switches environments; any key can be overridden with -DbaseUri=…. Passwords come from environment variables or the CI credential store — never from a committed file.
4. BaseTest with a shared specification
public abstract class BaseTest {
protected static RequestSpecification spec;
@BeforeSuite(alwaysRun = true)
public void setUpSpec() {
RestAssured.enableLoggingOfRequestAndResponseIfValidationFails();
spec = new RequestSpecBuilder()
.setBaseUri(ConfigReader.get("baseUri"))
.setContentType(ContentType.JSON)
.setAccept(ContentType.JSON)
.build();
}
}
5. A service layer
public class ProductService {
public static Response getAll() {
return given()
.spec(BaseTest.spec)
.get("/products");
}
public static Response getById(int id) {
return given()
.spec(BaseTest.spec)
.pathParam("id", id)
.get("/products/{id}");
}
}
Tests call ProductService.getById(1) instead of repeating request code — the same idea as page objects in UI automation. Full layer design: REST Assured Framework Design.
Sprint 1 — The First Smoke Suite
public class SmokeTest extends BaseTest {
@Test(groups = "smoke")
public void productListIsAvailable() {
List<Float> prices = ProductService.getAll()
.then()
.statusCode(200)
.body("size()", greaterThan(0))
.extract()
.jsonPath()
.getList("price", Float.class);
Assert.assertTrue(
prices.stream().allMatch(p -> p > 0),
"every price should be positive"
);
}
@Test(groups = "smoke")
public void productDetailMatchesContract() {
ProductService.getById(1)
.then()
.statusCode(200)
.body("id", equalTo(1))
.body(
matchesJsonSchemaInClasspath(
"schemas/product.json"
)
);
}
@Test(groups = "smoke")
public void loginReturnsToken() {
given()
.spec(spec)
.body(Map.of(
"username", ConfigReader.get("apiUser"),
"password", System.getenv("FAKESTORE_PASSWORD")
))
.when()
.post("/auth/login")
.then()
.statusCode(anyOf(is(200), is(201)))
.body("token", not(emptyOrNullString()));
}
@Test(groups = "smoke")
public void cartCanBeCreatedAndDeleted() {
int cartId = given()
.spec(spec)
.body(Map.of(
"userId", 1,
"products",
List.of(
Map.of(
"id", 1,
"quantity", 2
)
)
))
.when()
.post("/carts")
.then()
.statusCode(anyOf(is(200), is(201)))
.extract()
.path("id");
given()
.spec(spec)
.pathParam("id", cartId)
.when()
.delete("/carts/{id}")
.then()
.statusCode(200);
}
}
Run it with mvn test -Dgroups=smoke.
Fake Store's test credentials are listed in its documentation; set them as an environment variable rather than in the code. Fake Store simulates writes (a created cart isn't stored), so the delete checks the response code only — on your own API, follow a delete with a GET that expects 404. Its POST responses may return 200 or 201, hence the anyOf; on your project, assert the single documented code.
See how each smoke call moves through given(), when() and then() in the REST Assured Visualizer.
Wrap-up exercises
- Add the smoke group to a Jenkins or GitHub Actions job that runs on every build — see API Testing in CI/CD.
- Write a README: prerequisites, how to run each suite, how to switch environments, where reports appear.
- Push to Git with a
.gitignorefortarget/and local config files.
From Real Projects
My API testing experience covers CRUD operations, HTTP methods, JSON path, and validating JSON and XML data. On Testsigma, a platform that itself automates API tests, understanding requests, responses and status codes was part of understanding the product. Whatever tool you use, validate the status code, the response structure and the values — not just that the call returned something. Mocks let you test error paths that the real service can't easily produce. You may also find Practice REST Assured CI/CD, Contract & Senior Tasks useful.
📚 Official documentation: GraphQL: Learn · WireMock documentation
FAQs
What should you do before automating any API?
List and group the endpoints, mark auth and dependencies, rank criticality, choose smoke and regression candidates, and record it all in a coverage matrix.
How do you choose smoke APIs?
A few calls that prove the system is alive and the core journey works — login, key reads, one create — fast enough to run on every build.
Which REST Assured version should I use?
6.x on Java 17 or later; 5.5.x on Java 8 or 11. Don't add Groovy or JsonPath dependencies yourself.
Why externalise the base URI?
So the same suite runs against QA, staging or any other environment with a command-line switch instead of code changes.
What goes in the BaseTest?
Shared setup: a request specification with base URI and headers, logging on failure, and authentication if most tests need it. A closely related topic: REST Assured Practice.