Authors REST Assured (Java) API tests using the given().when().then() BDD-style DSL - status code + JSON/XML path assertions + authentication (Basic, OAuth2, API key). Configures Maven / Gradle dependencies, runs via JUnit 5, and emits Surefire / JaCoCo reports for CI gating. Use when the project is on the JVM and wants type-safe API tests in the app's own language; for a Gherkin feature-file flow on the same JVM use karate-testing, for YAML tests on the pytest stack use tavern-testing.
88
90%
Does it follow best practices?
Impact
88%
1.10xAverage score across 10 eval scenarios
Passed
No findings from the security scan
New joiner did the onboarding steps yesterday: clone, build, run the tests. The build failed on her machine because half the tests try to open HTTP connections to a server that isn't running. She spent the morning on it before someone told her the trick.
The trick is that everyone passes -Dtest='!*Api*' locally, and it isn't
written down anywhere. Two people have a shell alias for it. One person got
tired and put @Disabled on OrderApiTest.cancelsAnOrder "just for the
afternoon" - it has been off for three weeks and we only noticed when a
cancellation bug reached production.
The same thing hurts CI. Our first pipeline stage is meant to be the fast one that gives a signal in under a minute, and it takes nine minutes because it opens connections to staging. If staging is down, the fast stage goes red for reasons that have nothing to do with the change under review.
There are two kinds of test in this module and they are not distinguishable
from the outside: OrderMapperTest is pure in-process logic, OrderApiTest
talks HTTP.
Out of scope: do not change any test body, assertion, or endpoint - moving and renaming files is fine, editing what they assert is not.
Extract the following files before beginning.
=============== FILE: pom.xml =============== 4.0.0 com.acme orders 2.4.0-SNAPSHOT
21 UTF-8 io.rest-assured rest-assured 6.0.0 test org.junit.jupiter junit-jupiter 5.10.2 test maven-surefire-plugin 3.2.5=============== FILE: src/test/java/com/example/orders/OrderMapperTest.java =============== package com.example.orders;
import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
class OrderMapperTest {
@Test @DisplayName("cents are rendered with two decimals") void formatsAmount() { assertEquals("51.00", OrderMapper.formatCents(5100)); }
@Test @DisplayName("an unknown carrier code maps to UNKNOWN") void mapsUnknownCarrier() { assertEquals("UNKNOWN", OrderMapper.carrierName("ZZ")); } }
=============== FILE: src/test/java/com/example/orders/OrderApiTest.java =============== package com.example.orders;
import io.restassured.RestAssured; import io.restassured.http.ContentType; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.given; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.hasSize;
class OrderApiTest {
@BeforeAll static void setup() { RestAssured.baseURI = System.getProperty("api.baseURI", "http://localhost:8080"); }
@Test @DisplayName("an order can be fetched by id") void fetchesOrder() { given(). auth().oauth2(System.getenv("API_TOKEN")). accept(ContentType.JSON). when(). get("/v1/orders/42"). then(). statusCode(200). body("order_id", equalTo(42)). body("items", hasSize(greaterThan(0))); }
@Disabled("flaky since 2026-07-24, re-enable after the staging refresh") @Test @DisplayName("a placed order can be cancelled") void cancelsAnOrder() { given(). auth().oauth2(System.getenv("API_TOKEN")). accept(ContentType.JSON). when(). post("/v1/orders/43/cancel"). then(). statusCode(200). body("status", equalTo("cancelled")); } }