Q33 of 40 · REST Assured
How would you parallelise REST Assured tests safely? What can break?
Short answer
Short answer: REST Assured itself is thread-safe when you use local RequestSpecification instances — the thread-safety risk is static RestAssured.* fields. Replace all static fields with local specs or ThreadLocal wrappers. Test data isolation (unique resources per test) is the prerequisite; parallelism is the config layer on top.
Detail
What REST Assured makes thread-safe: the given().when().then() chain is stateless — each call creates new request/response objects. Multiple threads can build and send requests concurrently without interference.
What is NOT thread-safe:
RestAssured.baseURI = "..."— static field, shared across threadsRestAssured.requestSpecification = ...— static fieldRestAssured.port— static field
Fix: never use static RestAssured.* assignments; always use given(localSpec) with a locally-built spec.
What can break even with thread-safe code:
- Shared test data: two threads create a user with the same email → 409 Conflict. Fix: UUID-prefix every resource.
- Shared counters/sequences: tests that rely on the n-th record in the database break when n is non-deterministic in parallel. Fix: assert on specific IDs captured at creation time.
- Suite-scope shared mutable state: Wiremock stubs registered globally can interfere. Fix: use per-test stub scoping or @WireMockTest.
- Token expiry during a long parallel run: a token fetched at
@BeforeAllmay expire mid-suite. Fix: use the OAuth2Filter refresh pattern.
// EXAMPLE
ParallelSafeTest.java
// WRONG — static RestAssured fields, NOT thread-safe
static {
RestAssured.baseURI = "https://api.example.com"; // shared!
RestAssured.requestSpecification = reqSpec; // shared!
}
// CORRECT — local spec per test class, built in @BeforeAll
public abstract class BaseApiTest {
protected static RequestSpecification reqSpec; // immutable after build
@BeforeAll
static void buildSpecs() {
reqSpec = new RequestSpecBuilder()
.setBaseUri(System.getenv("API_BASE_URL")) // local, not static RestAssured.*
.addHeader("Authorization", "Bearer " + getToken())
.setContentType(ContentType.JSON)
.build(); // immutable — safe to share across threads
}
}
// Each test creates uniquely-named data to avoid collisions
@Test
void createUser_uniqueEmail_noCollisionInParallel() {
String uniqueEmail = "test-" + UUID.randomUUID() + "@example.com";
given(reqSpec)
.body(Map.of("name", "Alice", "email", uniqueEmail))
.when().post("/users")
.then().statusCode(201);
}