Q34 of 40 · REST Assured
How do you avoid flakiness in REST Assured tests that depend on shared state?
Short answer
Short answer: Root causes: shared mutable data (test A creates; test B deletes before A reads), time-dependent assertions, and implicit ordering. Fix with per-test data setup/teardown using UUID-prefixed resources, Awaitility for eventual-consistency endpoints, and explicit test independence so any test can run alone or in any order.
Detail
Root-cause analysis is the first step — categorise the flakiness before applying a fix:
Category 1 — Shared mutable test data: tests share a user/order/product; one test modifies or deletes it while another reads it. Fix: per-test isolation with unique resources created in @BeforeEach.
Category 2 — Eventual consistency: the API returns 201 but the data isn't readable yet (async indexing, cache propagation). Fix: Awaitility polling instead of an immediate GET.
Category 3 — Test order coupling: test B assumes test A ran first and left data behind. Fix: each test sets up its own data; run the suite in random order with @TestMethodOrder(MethodOrderer.Random.class) to catch hidden dependencies.
Category 4 — External service availability: tests that hit a real external API will flake when that API is slow or down. Fix: WireMock stubs for non-deterministic external dependencies.
Category 5 — Token expiry: a token fetched at suite start expires mid-run. Fix: the OAuth2Filter refresh pattern.
Flakiness tracking: quarantine persistently flaky tests with a @Tag("flaky") annotation and run them separately; measure the flake rate over a week before root-causing.
// EXAMPLE
// FLAKY — two tests sharing the same user ID
class FlakyUserTest {
@Test void updateUser_changesName() {
given(reqSpec).body(Map.of("name", "Bob"))
.when().put("/users/42").then().statusCode(200);
}
@Test void getUser_returnsAlice() { // flakes if updateUser runs first
given(reqSpec).when().get("/users/42")
.then().body("name", equalTo("Alice"));
}
}
// STABLE — each test creates and owns its data
class StableUserTest extends BaseApiTest {
private int userId;
@BeforeEach void create() {
userId = given(reqSpec)
.body(Map.of("name", "Alice", "email", "a-" + UUID.randomUUID() + "@test.com"))
.when().post("/users")
.then().statusCode(201).extract().<Integer>path("id");
}
@AfterEach void cleanup() {
given(reqSpec).when().delete("/users/" + userId)
.then().statusCode(anyOf(is(204), is(404)));
}
@Test void updateUser_changesName() {
given(reqSpec).body(Map.of("name", "Bob"))
.when().put("/users/" + userId).then().statusCode(200);
}
@Test void getUser_returnsAlice() {
given(reqSpec).when().get("/users/" + userId)
.then().body("name", equalTo("Alice"));
}
}