Что пишут в блогах

Подписаться

Онлайн-тренинги

Очные тренинги

Конференции

Что пишут в блогах (EN)

Разделы портала

Про инструменты

Лучшие вакансии

.
Тестирование PATCH-запросов
22.01.2019 00:00

Автор: Кристин Джеквони (Kristin Jackvony)

Оригинал статьи

Перевод: Ольга Алифанова.

Как и PUT-запросы, PATCH-запросы меняют существующую запись, однако их куда сложнее тестировать! PUT-запрос меняет запись целиком, а PATCH – только одну часть запроса. С PATCH-запросом можно проводить множество различных операций – вы можете добавлять, заменять, удалять, копировать и перемещать значения в вашей записи. Опишу несколько примеров, а потом поговорим о том, как это тестировать.


Давайте рассмотрим простой пример записи, которую мы будем менять:


JSON-описание первой записи будет выглядеть примерно так:

{
    "id": "1",
    "firstName": "John",
    "lastName": "Smith",
    "homePhone": "8005551000",
    "workPhone": null
}

Обратите внимание, что в первой записи отсутствует телефон. Проведем операцию добавления через PATCH-запрос, чтобы добавить номер.

URL для запроса будет примерно таким: https://app/customer/1, где 1 – это id пользователя, чьи данные мы изменяем, а HTTP-глагол для запроса будет, конечно, PATCH. Тело запроса будет выглядеть как-то так:

 [
    {"op":"add","path":"/workPhone","value":"8005551001"}
] 

"op" в этом случае относится к операции, которую вы выполняете через PATCH. Мы используем операцию "add", добавление. "Path" показывает, к какому полю добавляется значение (в этом случае это поле номера телефона); "value" – это то значение, которое вы передаете в это поле, в этом случае – сам номер.

Когда эта операция завершена, JSON-описание будет выглядеть примерно так:

{
    "id": 1,
    "firstName": "John",
    "lastName": "Smith",
    "homePhone": "8005551000",
    "workPhone": "8005551001"
}

Вот как можно тестировать операцию добавления PATCH:

  • Успешный сценарий: изменение отсутствующего значения.
  • Изменение отсутствующего значения через передачу пустого значения "" – должна добавиться пустая строка.
  • Изменение пустого значения "" – существующая пустая строка должна измениться.
  • Изменение существующего значения – оно должно быть заменено, но в идеале для этого используется операция замены "replace".
  • Добавление слишком длинного или слишком короткого значения по отношению к разрешенному – должно появиться соответствующее сообщение об ошибке.
  • Добавление значения с недопустимыми символами – должно появиться соответствующее сообщение об ошибке.
  • Добавление значения неверного типа, к примеру, числа там, где ожидается строка – должно появиться соответствующее сообщение об ошибке.

Теперь давайте рассмотрим операцию замены "replace". Обратимся к записи номер 2, и заменим домашний телефон. Запись пока что выглядит вот так:

{
    "id": 2,
    "firstName": "Amy",
    "lastName": "Jones",
    "homePhone": "8005551002",
    "workPhone": "8005551003"
}

URL для этого запроса - https://app/customer/2, потому что мы меняем вторую запись, а тело запроса будет таким:

 [
    {"op":"replace","path":"/homePhone","value":"8005551111"}
] 

Эта операция заменит исходный номер телефона 8005551002 номером 8005551111, и запись будет выглядеть так:

{
    "id": 2,
    "firstName": "Amy",
    "lastName": "Jones",
    "homePhone": "8005551111",
    "workPhone": "8005551003"
}

Вот что можно попробовать сделать, тестируя PATCH-операцию "replace":

  • Успешный сценарий: замена одного значения другим.
  • Замена значения на null – для этого больше подходит операция удаления "remove", но и замена должна сработать.
  • Замена значения на пустую строку "" – должно сработать.
  • Замена null-значения: возможно, это сработает, но лучше использовать "add".
  • Замена на слишком длинное или слишком короткое значение по сравнению с разрешенными – должно появиться соответствующее сообщение об ошибке.
  • Замена на значение с недопустимыми символами – должно появиться соответствующее сообщение об ошибке.
  • Замена на значение неверного типа – к примеру, на число там, где ожидается строка: должно появиться соответствующее сообщение об ошибке.
  • Замена там, где существующее значение по какой-то причине "плохое" – к примеру, слишком длинное или в неверном формате: в этом случае новое, "хорошее" значение должно успешно заменить "плохое" имеющееся.

Теперь давайте рассмотрим операцию удаления "remove". Начнем с этой записи:

{
    "id": 1,
    "firstName": "John",
    "lastName": "Smith",
    "homePhone": "8005551000",
    "workPhone": "8005551001"
}

Для удаления домашнего телефона этого пользователя мы снова воспользуемся URL: app/customer/1 и телом запроса, приведенным ниже:

 [
    {"op":"remove", "path":"/homePhone"}
] 

Вот что мы получим в результате:

{
    "id": "1",
    "firstName": "John",
    "lastName": "Smith",
    "homePhone": null,
    "workPhone": "8005551001"
}

Операцию "remove" довольно легко тестировать. Нам нужно убедиться, что значение действительно удалено и заменено на null. Также неплохо удостовериться, что никакие иные значения не удалились по ошибке (к примеру, что не удалены оба телефона, а не только домашний). Также можно проверить, что обязательное поле невозможно удалить – мы должны получить соответствующее сообщение об ошибке.

Перейдем к операции перемещения "move". Давайте посмотрим на предыдущее состояние записи "Джон" и представим, что она неверна – его рабочий телефон на самом деле его домашний. Чтобы переместить телефон, используем вот такое тело запроса:

 [
    {"op":"move","from":"/workPhone","path":"/homePhone"}
] 

В этом примере "from" обозначает, где сейчас находится значение, а "path" – куда вы его перемещаете. После этой операции запись будет выглядеть так:

{
    "id": "1",
    "firstName": "John",
    "lastName": "Smith",
    "homePhone": "8005551001",
    "workPhone": null
}

Ниже – идеи для тестирования операции "move":

  • Успешный сценарий: перемещение существующего значения туда, где значения нет.
  • Перемещение существующего значения из точки А в точку Б, при этом в точке Б уже есть значение. В этом случае значение Б будет заменено на значение, которое находилось в А.
  • Перемещение из А в Б, если значение А null: должно появиться сообщение об ошибке, потому что перемещать нечего.
  • Перемещение из А в Б в ситуации, когда ограничения в Б отличаются от ограничений А, и значение А недопустимо: должно появиться соответствующее сообщение об ошибке.
  • Перемещение из А в Б, если значение в А "плохое" – должно появиться соответствующее сообщение об ошибке.
  • Перемещение значения в локацию, которая не существует: должно появиться соответствующее сообщение об ошибке.

И, наконец, рассмотрим операцию копирования "copy". Она копирует существующее значение в другое место. Возьмем вот этот пример:

{
    "id": "1",
    "firstName": "John",
    "lastName": "Smith",
    "homePhone": "8005551001",
    "workPhone": null
}

Если мы хотим скопировать домашний телефон в поле рабочего телефона, мы выполним следующий запрос:

 [
    {"op":"copy","from":"/homePhone","path":"/workPhone"}
] 

Поле "from" показывает место, где находится значение, которое мы копируем, а "path" – куда его нужно скопировать. В результате запись будет выглядеть так:

{
    "id": "1",
    "firstName": "John",
    "lastName": "Smith",
    "homePhone": "8005551001",
    "workPhone": "8005551001"
}

Тестирование операции копирования очень похоже на тестирование операции перемещения:

  • Успешный сценарий: копирование существующего значения туда, где значения нет.
  • Копирование существующего значения из точки А в точку Б, при этом в точке Б уже есть значение. В этом случае значение Б будет заменено на значение, которое находилось в А.
  • Копирование из А в Б, если значение А null: должно появиться сообщение об ошибке.
  • Копирование значения в локацию, которая не существует: должно появиться соответствующее сообщение об ошибке.
  • Копирование из А в Б в ситуации, когда ограничения в Б отличаются от ограничений А, и значение А недопустимо: должно появиться соответствующее сообщение об ошибке.
  • Копирование из А в Б, если значение в А "плохое" – должно появиться соответствующее сообщение об ошибке.

Важно помнить, что PATCH-запросы могут выполняться цепочкой. К примеру, если мы начнем с этого сценария:

{
    "id": 2,
    "firstName": "Amy",
    "lastName": "Jones",
    "homePhone": "8005551002",
    "workPhone": "8005551003"
}

И отправим PATCH-запрос:

 [
    {"op":"remove","path":"/homePhone"},
    {"op":"replace","path":"/workPhone","value":"8005551111"}
] 

То результат будет таким:

{
    "id": 2,
    "firstName": "Amy",
    "lastName": "Jones",
    "homePhone": null,
    "workPhone": "8005551111"
}

Когда мы выполняем цепочку запросов PATCH, нужно протестировать, что любая невалидная операция приведет к невалидности запроса целиком. К примеру, если бы мы отправили такой запрос:

 [
    {"op":"remove","path":"/homePhone"},
    {"op":"replace","path":"/workPhone","value":"NOTAPHONENUMBER"}
] 

То мы получили бы сообщение об ошибке, и первая часть PATCH-запроса НЕ должна быть выполнена. Другими словами, домашний телефон все еще будет не пустым.

Как можно видеть, PATCH-запросы – это практически набор HTTP-глаголов! Их нужно использовать с особой осторожностью, потому что много чего может пойти не так. Если ваше приложение их использует, убедитесь, что вы протестировали их как по отдельности, так и в комбинации. Не забудьте протестировать и "счастливый путь", и способы, при которых нарушится валидация. Если база данных допускает "плохие" значения, не забудьте проверить патч поверх этих значений.

Больше информации по этой теме вы можете получить в курсе Тестирование REST API

Обсудить в форуме