Как реализовать ожидание (wait/polling) для ответа API в автотестах?

«Как реализовать ожидание (wait/polling) для ответа API в автотестах?» — вопрос из категории API тестирование, который задают на 24% собеседований AQA / Automation. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Ожидание ответа от API — стандартная задача в интеграционном и E2E-тестировании, особенно для асинхронных операций (например, запуск долгой задачи). Основные подходы:

1. Явный поллинг (Explicit Polling) с таймаутом

Наиболее прямой и контролируемый способ. Цикл проверяет условие с заданным интервалом до истечения таймаута.

import java.time.Duration;
import java.time.Instant;

public class ApiPoller {
    public static JsonPath waitForJobCompletion(String jobId, Duration timeout, Duration interval) {
        Instant endTime = Instant.now().plus(timeout);
        while (Instant.now().isBefore(endTime)) {
            Response response = RestAssured.given().get("/api/jobs/" + jobId);

            if (response.statusCode() == 200) {
                String status = response.jsonPath().getString("status");
                if ("COMPLETED".equals(status)) {
                    return response.jsonPath(); // Успех, возвращаем данные
                } else if ("FAILED".equals(status)) {
                    throw new RuntimeException("Job " + jobId + " failed");
                }
                // Статус "RUNNING" или "PENDING" — продолжаем ждать
            }
            try {
                Thread.sleep(interval.toMillis()); // Интервал между запросами
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new RuntimeException("Polling interrupted", e);
            }
        }
        throw new RuntimeException("Job did not complete within " + timeout);
    }
}
// Использование
JsonPath result = ApiPoller.waitForJobCompletion("job-123", Duration.ofSeconds(30), Duration.ofSeconds(2));

2. Использование библиотек для Retry/Polling

Упрощают код и добавляют продвинутые функции (экспоненциальная задержка, обработка исключений).

  • Java + Awaitility:

    import static org.awaitility.Awaitility.*;
    
    await().atMost(30, SECONDS)
           .pollInterval(2, SECONDS)
           .until(() -> {
               Response r = get("/api/status");
               return r.statusCode() == 200 && 
                      r.jsonPath().getString("state").equals("READY");
           });

3. Ожидание по событию (Webhook / Callback) — более продвинутый подход

Вместо поллинга система сама уведомляет тестовый фреймворк о завершении через обратный вызов (callback URL) или сообщение в очередь (Kafka, RabbitMQ). Это наиболее эффективно для долгих операций.

Критерии выбора подхода для QA:

  • Поллинг подходит для быстрых операций (до 30-60 сек) и когда нельзя модифицировать тестируемую систему.
  • Webhook/Callback предпочтительнее для долгих фоновых задач, так как не нагружает систему лишними запросами.
  • Обязательно настраивайте таймауты на основе SLA системы.
  • Логируйте шаги поллинга для отладки.
  • Избегайте «жестких» Thread.sleep() в пользу конфигурируемых интервалов.