Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Тестирование PATCH-запросов: подход и практический пример
PATCH — это HTTP-метод для частичного обновления ресурса. В отличие от PUT, который заменяет ресурс целиком, PATCH позволяет изменять только указанные поля, что делает его более эффективным и безопасным для больших объектов. Тестирование PATCH требует особого внимания, так как связано с проверкой частичных изменений, валидации и обработки граничных случаев.
Ключевые аспекты тестирования PATCH
При тестировании PATCH-эндпоинтов я проверяю следующие сценарии:
- Позитивное тестирование:
* Обновление одного поля.
* Обновление нескольких полей одновременно.
* Обновление с корректными типами данных (строка, число, булево значение).
* Проверка, что неизменяемые поля (например, `id`, `createdAt`) остались прежними.
* Корректный HTTP-статус ответа (обычно `200 OK` или `204 No Content`).
- Негативное тестирование и валидация:
* Отправка некорректного JSON.
* Попытка обновления несуществующим типом данных (например, строку вместо числа).
* Попытка обновления несуществующего поля (поведение зависит от API: должно либо игнорироваться, либо возвращать ошибку).
* Передача пустого тела запроса.
* Обновление несуществующего ресурса (должен возвращаться `404 Not Found`).
* Проверка валидации бизнес-логики (например, нельзя установить отрицательный возраст).
- Тестирование безопасности и прав доступа:
* Вызов без авторизации (`401 Unauthorized`).
* Вызов с недостаточными правами (например, попытка изменить чужой профиль, `403 Forbidden`).
* Проверка на инъекции (например, SQL- или NoSQL-инъекции через строковые поля).
Практический пример: PATCH /api/users/{id}
Предположим, у нас есть API для управления пользователями. Эндпоинт PATCH /api/users/123 обновляет данные пользователя с id=123. Текущее состояние ресурса:
{
"id": 123,
"username": "old_user",
"email": "old@example.com",
"age": 25,
"isActive": true
}
Тест-кейс 1: Успешное обновление нескольких полей
Шаги:
- Отправить PATCH-запрос с валидным токеном авторизации.
- Тело запроса:
{ "username": "new_username", "age": 26 } - Ожидаемый результат:
* Статус-код: `200 OK`.
* Тело ответа содержит обновлённый объект. Поля `username` и `age` изменены, а `email` и `isActive` остались прежними.
```json
{
"id": 123,
"username": "new_username",
"email": "old@example.com",
"age": 26,
"isActive": true
}
```
4. Дополнительная проверка: Выполнить GET-запрос к тому же ресурсу, чтобы убедиться, что изменения действительно сохранились в базе данных.
Тест-кейс 2: Попытка обновления несуществующего поля (должно игнорироваться)
# Пример запроса с использованием curl
curl -X PATCH https://api.example.com/users/123 \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"unknownField": "someValue", "age": 30}'
Ожидаемый результат: Поле unknownField проигнорировано, поле age обновлено до 30. В ответе не должно быть поля unknownField.
Тест-кейс 3: Обработка невалидных данных
Шаги:
- Отправить PATCH-запрос с некорректным значением для поля
age(ожидается положительное число).{"age": -5} - Ожидаемый результат:
* Статус-код: `400 Bad Request` или `422 Unprocessable Entity`.
* Тело ответа содержит сообщение об ошибке валидации.
```json
{
"error": "Validation failed",
"details": {"age": "Must be a positive number"}
}
```
Тест-кейс 4: Автоматизированный тест на Python (с использованием pytest и requests)
import pytest
import requests
BASE_URL = "https://api.example.com"
USER_ID = 123
AUTH_TOKEN = "valid_token_here"
def test_patch_user_partial_update():
"""Тест частичного обновления пользователя."""
headers = {
"Authorization": f"Bearer {AUTH_TOKEN}",
"Content-Type": "application/json"
}
payload = {
"email": "updated@example.com",
"isActive": False
}
response = requests.patch(
f"{BASE_URL}/users/{USER_ID}",
json=payload,
headers=headers
)
# Проверка статус-кода
assert response.status_code == 200, f"Expected 200, got {response.status_code}"
# Проверка обновлённых полей в ответе
response_data = response.json()
assert response_data["email"] == "updated@example.com"
assert response_data["isActive"] is False
# Проверка, что другие поля не изменились
assert response_data["id"] == USER_ID
assert "username" in response_data # Поле осталось
def test_patch_user_nonexistent():
"""Тест обновления несуществующего пользователя."""
headers = {"Authorization": f"Bearer {AUTH_TOKEN}"}
response = requests.patch(
f"{BASE_URL}/users/99999",
json={"username": "test"},
headers=headers
)
assert response.status_code == 404
def test_patch_user_unauthorized():
"""Тест обновления без авторизации."""
response = requests.patch(
f"{BASE_URL}/users/{USER_ID}",
json={"username": "hacker"}
)
assert response.status_code == 401
Важные замечания по тестированию
- Идемпотентность: PATCH не является идемпотентным по умолчанию (в отличие от PUT). Повторный запрос с тем же телом может привести к другому результату (например, инкремент счётчика). Это нужно явно тестировать, если такая логика заложена в API.
- Формат запроса: Важно согласовать с разработчиками формат изменений. Это может быть JSON Merge Patch (простой JSON, как в примерах выше) или JSON Patch (RFC 6902), который использует массив операций (
add,remove,replace,move,copy,test). Подход к тестированию будет разным. - Консистентность данных: После PATCH-запроса критически важно проверять не только ответ, но и актуальное состояние данных через GET, а также влияние изменений на связанные сущности.
Таким образом, тестирование PATCH — это комплексная задача, требующая проверки функциональности, валидации, безопасности и целостности данных. Автоматизация таких тестов, как показано в примере, является обязательной частью процесса обеспечения качества современного API.