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

Приведи пример бага при тестировании API

1.0 Junior🔥 261 комментариев
#Работа с дефектами

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

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

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

Пример бага при тестировании REST API: нарушение согласованности данных

Одним из классических и критичных багов, который часто обнаруживается при тестировании API, является нарушение идемпотентности метода POST при создании ресурса, ведущее к дублированию данных и несогласованности состояния системы.

Контекст и предпосылки

Предположим, мы тестируем API интернет-магазина. Есть endpoint для создания заказа: POST /api/v1/orders Тело запроса (JSON):

{
  "customer_id": 12345,
  "items": [
    {"product_id": 777, "quantity":1463253532}
  ]
}

По бизнес-логике, каждый уникальный заказ должен создаваться один раз. Клиент (фронтенд или мобильное приложение) после отправки формы может, например, из-за плохой сети отправить запрос повторно, или пользователь дважды нажмет кнопку "Оформить заказ".

Воспроизведение бага

  1. Шаг 1: Тестировщик отправляет корректный POST /api/v1/orders запрос для создания заказа.
    curl -X POST https://api.store.com/api/v1/orders \
      -H "Authorization: Bearer token123" \
      -H "Content-Type: application/json" \
      -d '{"customer_id": 12345, "items": [{"product_id": 777, "quantity": 2}]}'
    
    Сервер отвечает кодом `201 Created` и возвращает тело с созданным заказом, включая его новый `id: 1001`.

  1. Шаг 2 (имитация проблемы сети или двойного клика): БЕЗ ИЗМЕНЕНИЙ отправляется точно такой же запрос с идентичными заголовками и телом.
    **Ожидаемое поведение (согласно принципам REST):**
    *   Сервер должен вернуть код `409 Conflict` или `400 Bad Request` с сообщением, что заказ уже существует.
    *   **Или (оптимальный вариант):** Сервер должен реализовывать **идемпотентность через ключ идемпотентности (idempotency-key)**, переданный в заголовке, и при повторном запросе с тем же ключом возвращать тот же успешный ответ (`201 Created` с данными заказа `id: 1001`), **но НЕ создавать новый заказ**.

  1. Фактическое поведение (баг): Сервер отвечает на второй идентичный запрос также кодом 201 Created, но в теле ответа возвращает новый объект заказа с другим id: 1002.
    {
      "id": 1002,
      "customer_id": 12345,
      "items": [{"product_id": 777, "quantity": 2}],
      "status": "new"
    }
    

Последствия и критичность бага

Этот баг имеет уровень критичности Critical или Blocker:

  • Финансовые потери: Пользователю будет списана сумма за заказ дважды (если оплата привязана к созданию). Клиент получит два идентичных товара вместо одного.
  • Нарушение бизнес-логики: В системе возникают дубликаты данных, что делает невалидной любую аналитику (например, количество уникальных заказов).
  • Проблемы с последующими операциями: С каким из заказов (1001 или 1002) должен работать пользователь при попытке оплаты или отмены? Это вносит путаницу.
  • Деградация пользовательского опыта: Клиент теряет доверие к приложению.

Корень проблемы (Root Cause)

Причина обычно кроется в слое бизнес-логики или базы данных:

  • Отсутствие проверки на дублирование на основе ключевых полей (например, хэша от содержимого запроса + customer_id + временной метки в рамках окна).
  • Неправильная реализация транзакции в БД или отсутствие UNIQUE CONSTRAINT на комбинацию полей, которая должна гарантировать уникальность заказа в определенном статусе.
  • Отсутствие механизма идемпотентных ключей (Idempotency-Key) для операций POST.

Рекомендации по исправлению

  1. Внедрить заголовок Idempotency-Key: Клиент генерирует уникальный ключ для операции и отправляет его в заголовке, например, Idempotency-Key: uuid_от_клиента. Сервер кеширует ответ на первый запрос с этим ключом и возвращает его при всех последующих.
  2. Добавить проверку дубликатов: Перед вставкой нового заказа проверять наличие "похожего" недавно созданного заказа для этого пользователя.
  3. Использовать уникальные ограничения в БД: Если бизнес-Logic это позволяет, создать UNIQUE CONSTRAINT на комбинацию customer_id, status и hash_of_items.
  4. Вернуть корректный HTTP -status: В случае обнаружения потенциального дубликата возвращать 409 Conflict с понятным описанием ошибки в теле ответа.

Этот пример наглядно показывает, что тестирование API — это не только проверка формата JSON или HTTP-кодов, но и глубокая проверка консистентности данных, бизнес-логики и следования принципам проектирования (REST).