← Назад к вопросам

Какие знаешь неидемпотентные запросы?

2.2 Middle🔥 201 комментариев
#Теория тестирования#Фреймворки тестирования

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Неидемпотентные запросы в веб-разработке и тестировании API

В контексте QA Automation, особенно при тестировании API, понимание концепции идемпотентности и её противоположности — неидемпотентности — критически важно для построения корректных, безопасных и воспроизводимых тестов. Неидемпотентный запрос — это операция, которая при повторном выполнении с одинаковыми параметрами приводит к разному состоянию системы или возвращает разный результат. В отличие от идемпотентных методов (GET, PUT, DELETE в идеальном мире), неидемпотентные меняют данные или состояние каждый раз.

Основные примеры неидемпотентных HTTP методов и операций

1. HTTP метод POST

Стандартный пример неидемпотентности. Используется для создания новых ресурсов.

  • Повторный вызов одного и того же POST запроса (например, на /api/users с данными нового пользователя) создаст две одинаковые записи в базе данных, что изменит состояние системы (число пользователей увеличится вдвое).
  • Ответы также будут разными: первый запрос вернет ID нового ресурса (например, 201), второй — другой ID (например, 202).
POST /api/orders
Content-Type: application/json

{
  "productId": 123,
  "quantity": 2
}

Выполнение этого запроса дважды создаст два независимых заказа.

2. HTTP метод PATCH (в большинстве случаев)

Часто используется для частичного обновления ресурса. Его идемпотентность зависит от логики операции.

  • Пример неидемпотентного PATCH: уменьшение баланса пользователя ({"action": "decrement", "amount": 100}). Двойное выполнение уменьшит баланс на 200.
  • Пример идемпотентного PATCH: установка конкретного значения ({"status": "completed"}). Повторное выполнение не изменит результат.
PATCH /api/accounts/456/balance
Content-Type: application/json

{
  "operation": "withdraw",
  "amount": 50
}

Повторный вызов приведет к списанию 100 вместо 50.

3. Неидемпотентные действия внутри PUT или DELETE

Иногда даже методы, считающиеся идемпотентными, могут быть неидемпотентными из-за бизнес-логики.

  • PUT запрос, который увеличивает счетчик (например, {"viewCount": currentCount + 1}) — неидемпотентен. Повторное выполнение будет каждый раз увеличивать значение.
  • DELETE запрос, который перед удалением выполняет стороннее действие (например, отправляет уведомление или списывает комиссию) — также может считаться неидемпотентным, если эти действия происходят при каждом вызове.
PUT /api/articles/789
Content-Type: application/json

{
  "views": "increment"
}

Логика increment делает запрос неидемпотентным.

Практическое значение для QA Automation Engineer

Для автоматизатора тестирования API это имеет следующие ключевые следствия:

  • Планирование тестовых сценариев: Тесты для неидемпотентных операций должны учитывать необходимость предварительного очищения состояния (setup) или восстановления данных после теста (teardown). Часто используется подход @BeforeEach/@AfterEach или прямая очистка БД.
  • Тестирование на повторные вызовы (Retry): Проверка поведения системы при дублировании запроса (например, двойной клик "Отправить" в UI) — важный тест-кейс. Система должна либо предотвращать дублирование (через токены), либо корректно обрабатывать его.
  • Воспроизводимость тестов: Неидемпотентные тесты сложно воспроизводить без четкой стратегии управления данными. Необходимо использовать уникальные идентификаторы (timestamp, UUID) в запросах или работать с изолированными тестовыми данными.
  • Тестирование параллельных запросов (Concurrency): Неидемпотентные операции, особенно финансовые (списание средств), требуют тестирования в условиях параллельного выполнения для проверки транзакционной безопасности и отсутствия race conditions.
// Пример теста для неидемпотентного POST в Java (RestAssured)
@Test
public void testNonIdempotentPostCreatesNewResourceEachTime() {
    // 1. Первый запрос - создаем ресурс
    OrderRequest orderBody = new OrderRequest(123, 2);
    Response firstResponse = RestAssured
            .given()
            .contentType(ContentType.JSON)
            .body(orderBody)
            .post("/api/orders");
    int firstOrderId = firstResponse.jsonPath().getInt("id");

    // 2. Второй ИДЕНТИЧНЫЙ запрос - создаем еще один ресурс
    Response secondResponse = RestAssured
            .given()
            .contentType(ContentType.JSON)
            .body(orderBody) // То же тело!
            .post("/api/orders");
    int secondOrderId = secondResponse.jsonPath().getInt("id");

    // 3. Проверка неидемпотентности: IDs должны быть разными
    Assert.assertNotEquals(firstOrderId, secondOrderId);

    // 4. Проверка состояния системы: теперь должно быть 2 заказа
    Response listResponse = RestAssured.get("/api/orders");
    List<Integer> allIds = listResponse.jsonPath().getList("id");
    Assert.assertTrue(allIds.contains(firstOrderId) && allIds.contains(secondOrderId));
}

Таким образом, для QA Automation специалиста глубокое понимание неидемпотентных запросов — это не просто теория, а основа для разработки надежных, воспроизводимых и полных тестовых стратегий, особенно в областях, связанных с созданием данных, финансовыми транзакциями и операциями, изменяющими состояние системы.

Какие знаешь неидемпотентные запросы? | PrepBro