Q32 of 40 · REST Assured

How do you handle long-polling or async API responses in REST Assured?

REST AssuredSeniorrest-assuredasyncawaitilitypollingapi-testing

Short answer

Short answer: Poll the status endpoint with Awaitility — define a condition (statusEquals("COMPLETE")), a poll interval, and a timeout. REST Assured fires the GET inside the Awaitility lambda; Awaitility handles retries. Never Thread.sleep() in tests — it makes them slow, brittle, and sensitive to environment speed.

Detail

Async APIs (job queues, document processing, webhooks) return a job ID immediately and the result asynchronously. Tests need to wait for completion without a fixed sleep:

// Awaitility + REST Assured
await().atMost(30, SECONDS).pollInterval(2, SECONDS)
    .untilAsserted(() ->
        given(reqSpec)
            .when().get("/jobs/" + jobId)
            .then().statusCode(200)
                   .body("status", equalTo("COMPLETE"))
                   .body("result.recordsProcessed", greaterThan(0))
    );

untilAsserted runs the entire lambda (including REST Assured assertions) — if any assertion fails, Awaitility retries up to the timeout. If it succeeds, the test moves on immediately.

until vs untilAsserted:

  • until — expects a boolean-returning lambda; good for simple state checks
  • untilAsserted — expects a lambda that throws on failure; best with REST Assured assertions

Configuring poll intervals: use exponential backoff (pollInSameThread().pollDelay(Duration.ofSeconds(1)).pollInterval(fibonacci())) for jobs with variable completion times.

Webhook testing: start a mock server (WireMock), trigger the action, wait for WireMock to capture the incoming webhook, then assert its payload.

// EXAMPLE

@Test
void importJob_completesWithinTimeout_andReportsCount() {
    File csvFile = new File("src/test/resources/1000-users.csv");

    // Trigger async job
    String jobId = given(reqSpec)
        .multiPart("file", csvFile, "text/csv")
    .when()
        .post("/imports")
    .then()
        .statusCode(202)
        .body("status", equalTo("QUEUED"))
        .extract().path("jobId");

    // Poll until complete (max 60s, check every 3s)
    await().atMost(60, SECONDS).pollInterval(3, SECONDS)
        .untilAsserted(() ->
            given(reqSpec)
                .when().get("/imports/" + jobId)
                .then()
                    .statusCode(200)
                    .body("status",                 equalTo("COMPLETE"))
                    .body("result.successCount",    equalTo(1000))
                    .body("result.errorCount",      equalTo(0))
        );
}

// WHAT INTERVIEWERS LOOK FOR

Using Awaitility rather than Thread.sleep(), correct use of untilAsserted() for REST Assured assertion lambdas, and a concrete poll interval / timeout strategy. Mentioning webhook testing with WireMock is a senior bonus.

// COMMON PITFALL

Thread.sleep(10000) to wait for async jobs. This is fragile (fails if the job takes 11 seconds), wastes time (waits the full 10 seconds even if the job completes in 2), and is hard to tune across environments with different speeds.