В чем опасность метода PUT при тестировании API?

Ответ

Основная опасность метода PUT с точки зрения тестирования заключается в его идемпотентности — повторный вызов с теми же данными полностью перезаписывает ресурс. Это может привести к следующим рискам, которые необходимо проверять в тестах:

  • Потеря данных: Если клиент отправляет запрос с неполным представлением ресурса (например, только одно поле), сервер может заменить весь существующий ресурс, удалив остальные поля. Тесты должны проверять, как API обрабатывает такие неполные запросы.
  • Нарушение целостности данных (Race Conditions): Если два параллельных PUT-запроса приходят к одному ресурсу, последний выиграет, что может привести к потере изменений из первого запроса. Это требует тестирования на конкурентность.
  • Проблемы с безопасностью: Без должной авторизации PUT может позволить перезаписать конфиденциальные данные другого пользователя.

Пример сценария для тестирования:

# Исходное состояние ресурса
GET /api/users/123
{
  "id": 123,
  "name": "Иван",
  "email": "ivan@example.com",
  "role": "user"
}

# PUT-запрос, изменяющий только имя
PUT /api/users/123
Content-Type: application/json
{"name": "Петр"}

# Ожидаемый результат зависит от реализации API.
# Плохой сценарий (полная замена):
GET /api/users/123
{"name": "Петр"} # Поля email и role потеряны!

# Хороший сценарий (валидация или использование PATCH):
# API должен вернуть ошибку 400 Bad Request или 422 Unprocessable Entity,
# требуя отправки полного представления ресурса.

Что проверять в тестах:

  1. Валидация входящих данных (требуется ли полное представление ресурса?).
  2. Механизмы предотвращения конфликтов (заголовки ETag, If-Match).
  3. Корректная обработка конкурентных запросов.
  4. Строгая проверка прав доступа (может ли пользователь A изменить ресурс пользователя B?).

Ответ 18+ 🔞

А, ну ты держись, сейчас расскажу про эту вашу идемпотентность, которая всех так ебёт. Смотри, метод PUT — он как тот упоротый сосед, который приходит к тебе в гости и, не спрашивая, вываливает все твои вещи из шкафа, а на их место ставит свой одинокий свитер. И так может делать хоть сто раз подряд — результат один: твои вещи в жопе, а его свитер торжественно лежит на полке. Это и есть идемпотентность, ёпта. Повторяешь действие — получаешь тот же пиздец.

Основная засада, которую надо ловить тестами, — это три кита дерьма, на которых держится кривая реализация.

Первый кит — потеря данных, овердохуища какая. Представь: у пользователя в базе имя, почта, роль. Какой-то криворукий клиент шлёт PUT-запрос, где только поле "name" обновлено. А сервер-дурак, не глядя, берёт и хуяк — заменяет всю запись в базе на этот кусок JSON. И всё, пиши пропало: почта и роль накрылись медным тазом. Пользователь теперь просто «Петя» без почты и прав. Красота, да? Тесты должны этот сценарий гонять по полной: а что будет, если отправить неполные данные? API должен либо орать, что ему не хватает полей (ошибка 400 или 422), либо сам дозаполнять недостающее из старой версии. Но ни в коем случае не молча всё стирать!

Второй кит — гонки (Race Conditions), или «гомосеки налетели». Ситуация: два запроса летят на сервер одновременно, чтобы обновить одну и ту же сущность. Один хочет поменять имя, другой — почту. Кто прилетел последним, тот и прав. В итоге побеждает второй запрос, а изменения из первого — просто испаряются, как будто их и не было. Пользователь думает, что имя обновил, а на деле там уже совсем другие данные. Тестами надо имитировать эту адскую гонку и смотреть, как API будет выкручиваться: может, через заголовки ETag или If-Match, чтобы конфликты обнаруживать.

Третий кит — безопасность, тут доверия ебать ноль. Если не проверить права доступа, то любой шутник может отправить PUT на чужой ресурс и перезаписать его. Ты был админом, а стал гостем. Всё, приехали. Тесты должны долбить эту границу: а может ли юзер А ебнуть ресурс юзера Б? Если может — это пиздец, а не API.

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

# Исходное состояние ресурса
GET /api/users/123
{
  "id": 123,
  "name": "Иван",
  "email": "ivan@example.com",
  "role": "user"
}

# PUT-запрос, изменяющий только имя
PUT /api/users/123
Content-Type: application/json
{"name": "Петр"}

# Ожидаемый результат зависит от реализации API.
# Плохой сценарий (полная замена):
GET /api/users/123
{"name": "Петр"} # Поля email и role потеряны! Вот это пизда рулю!

# Хороший сценарий (валидация или использование PATCH):
# API должен вернуть ошибку 400 Bad Request или 422 Unprocessable Entity,
# требуя отправки полного представления ресурса.

Итак, что тесты должны делать, чтобы все спать спокойно могли:

  1. Валидация входящих данных — а что, если прислали хуйню? А если не всё? API должен чётко сказать: «Чувак, ты мне не полный объект прислал, иди нахуй с таким PUT'ом, используй PATCH или присылай всё».
  2. Механизмы предотвращения конфликтов — проверяй работу с ETag и If-Match. Чтобы если данные уже кто-то успел поменять, второй запрос не затёр их, как говно.
  3. Конкурентные запросы — устраивай настоящую бойню, гони десятки параллельных запросов на один ресурс. Смотри, чтобы данные не превратились в кашу.
  4. Проверка прав доступа — это святое. Под разными пользователями пытайся трогать чужие ресурсы. Если прокатило — значит, пора бить в колокола и нестись с криком «вилкой в глаз или в жопу раз» к разработчикам.

Вот так-то, дружище. PUT — он мощный, но опасный, как хуй с горы. Не тестируешь его — готовься к сюрпризам, от которых сам от себя охуеешь.