Как вручную тестировать API WebSocket

🔥 Важное для QA-специалистов! 🔥
В QaRocks ты найдешь туториалы, задачи и полезные книги, которых нет в открытом доступе. Уже более 15.000 подписчиков – будь среди нас! Заходи к нам в телеграм канал QaRocks

Перевод статьи «How to Manually Test WebSocket APIs».

Если вы когда-либо тестировали HTTP API, то не столкнетесь с большими трудностями при тестировании двунаправленных сообщений. Однако есть несколько особенностей, присущих WebSockets, которые следует принять во внимание перед началом тестирования.

Теория

WebSocket — это постоянное соединение между клиентом и сервером. WebSockets обеспечивают двунаправленный канал связи (позволяет осуществлять связь в обоих направлениях одновременно) через одно соединение TCP/IP.

Благодаря соединению WebSocket связь между клиентом и сервером может происходить в режиме реального времени (в отличие от HTTP с потерями времени на каждый запрос/ответ), подобно UDP, но с надежностью TCP. Поэтому он широко используется в чатах, играх и браузерных приложениях фондового рынка.

WebSocket начинается с установления соединения (handshake), за которым следует основной обмен сообщениями:

Рис. 1 WebSockets

Соединение вебсокет устанавливается путем обновления HTTP-запроса. Клиент (в большинстве случаев под клиентом подразумевается веб-браузер), поддерживающий WebSocket API и желающий установить соединение, должен отправить HTTP-запрос с заголовками, специфичными для WebSocket:

  • Connection: keep-alive, upgrade — наиболее частым значением для этого заголовка является «keep-alive», чтобы сделать соединение постоянным, что позволяет выполнять последующие запросы к этому же серверу. Значение «Upgrade» используется для перевода соединения на другой протокол;
  • Upgrade: websocket — указывает протокол для обновления;
  • Sec-WebSocket-Key: ключ — это одноразовое случайное значение, генерируемое клиентом для подтверждения того, что он имеет право запрашивать обновление протокола на WebSocket;
  • Sec-WebSocket-Version: число — указывает версию протокола WebSocket, которую хочет использовать клиент.

Минимально необходимый запрос выглядит следующим образом:

GET /socket HTTP/1.1
Host: polkadot.webapi.subscan.io
Connection: keep-alive, upgrade
Upgrade: websocket
Sec-WebSocket-Key: N509hQQwSFGfanhbxP3F6g==
Sec-WebSocket-Version: 13

Если все прошло успешно, сервер ответит кодом ответа «HTTP 101 Switching Protocols» с дополнительными заголовками:

  • Connection: upgrade
  • Upgrade: websocket
  • Sec-WebSocket-Accept: keyсообщает, что сервер готов инициировать WebSocket-соединение.

В реальной жизни handshake выглядит следующим образом (в следующих примерах я буду использовать запросы на сайте Subscan.io):

Рис. 2. Детали сетевого запроса WebSocket в Firefox DevTools

После того как клиент получает ответ от сервера, открывается вебсокет-соединение, чтобы начать передачу данных в виде сообщений, в соответствии с протоколом WebSocket. Не вдаваясь в подробности, под «сообщениями» подразумевается полезная нагрузка/тело (в большинстве случаев это текст) в сообщениях между клиентом и сервером:

Рис. 3. Здесь сервер постоянно отправляет сообщения клиенту. В этом случае тело сообщения представлено в виде JSON, но формат может быть любым

Как только обе стороны подтвердят, что соединение должно быть закрыто, TCP-соединение будет разорвано.

Дополнительные материалы:

Инструменты

Браузеры

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

Вы можете увидеть все вебсокет соединения в DevTools (как показано на скриншоте выше) и даже взаимодействовать с ними через консоль браузера при помощи WebSocket API.

Вся основная функциональность умещается в нескольких командах:

1. Открываем соединение:

const ws = new WebSocket('wss://polkadot.webapi.subscan.io/socket');

2. Получаем сообщения:

ws.onmessage = function (e) { console.log(e.data) };

3. Отправляем сообщения:

ws.send('hello world');

4. Закрываем соединение:

ws.close();
Рис. 4. Работа с WebSockets в консоли через WebSocket API

В консоли браузера удобно сделать смоук тестирование, чтобы проверить, что соединение вообще можно установить.

Дополнительные материалы:

Wscat

Любители CLI будут разочарованы ограниченным набором инструментов для работы с WebSockets из терминала (к сожалению, даже libcurl не поддерживает WebSockets). Фактически, есть только один пригодный для использования CLI-инструмент — wscat.

Он устанавливается как npm пакет:

npm install -g wscat

И сразу же готов к работе:

wscat -c 'wss://polkadot.webapi.subscan.io/socket'
Рис. 5. wscat

Postman

Этот «швейцарский нож тестировщика» получил поддержку вебсокетов всего год назад, но она доступна только после входа в «рабочее пространство«. Несмотря на то, что вебсокеты в Postman все еще находится в бета-версии, текущей функциональности вполне достаточно для тестирования API.

Нажмите на кнопку создания нового запроса, а на экране выбора протокола выберите «WebSocket Request»:

Рис. 6 Новый «Запрос WebSocket» в Postman

С помощью следующего интерфейса (он немного отличается от обычной формы для HTTP-запросов) вы можете легко создавать вебсокет-запросы, а также отправлять и получать сообщения.

Рис. 7. Интерфейс запросов WebSocket в Postman

На данный момент в Postman нет вкладки «Тесты» для автоматизации тестов, как в интерфейсе HTTP-запросов. Таким образом, тестирование вебсокетов осуществляется вручную. Описание остальных возможностей выходит за рамки этой статьи, к тому же документация очень подробная.

Дополнительные материалы:

Практика

WebSocket API — это API, поэтому к WebSockets можно применять все те же стратегии тестирования, что и при тестировании REST API. Это значит, что основные проверки не будут сильно отличаться от обычного тестирования HTTP API:

  • Проверьте правильность методов и кодов состояния;
  • Проверьте полезную нагрузку запроса и ответа;
  • Проверьте нефункциональные требования: время отклика, производительность, безопасность и т. д.

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

  • Проверка правильности реализации протокола;
  • Тестирование бизнес-логики.

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

Проверка правильности реализации

Как было описано в теоретической части статьи, начальным этапом подключения по вебсокету является handshake, и все доступные инструменты выполняют его автоматически. Это очень удобно, но не оставляет места для ручного тестирования, поскольку привычные HTTP-инструменты не работают с WebSockets — даже сами браузеры не делают WebSocket-запросы за пределами исходной веб-страницы:

Рис. 8. Ничего не произойдет, если попытаться открыть URL-адрес WebSockets на новой странице

Остается только следующие варианты:

  • Позитивный тест: соединение должно быть установлено через фронтенд в браузере.

Перезагрузите веб-страницу и проверьте код состояния HTTP = 101, а также убедитесь, что браузер начал обмениваться сообщениями с сервером:

Рис. 9 и 10. Информация о вебсокет соединении в Chromium
  • Негативный тест: соединение не должно устанавливаться по недопустимому протоколу.

Запрашивайте URL вебсокета как обычный HTTPS-запрос вместо WSS.

Рис. 11. «400 Bad Request» — ожидаемый результат

Другой стороной этого случая может быть попытка установить незащищенное соединение. Существует два типа протокола WebSocket:

  • ws подключается по протоколу HTTP;
  • wss подключается только по протоколу HTTPS (защищенный).
Рис. 12. Не удалось подключиться к ws://polkadot.webapi.subscan.io/socket — ожидаемый результат.
  • Позитивный тест: соединение должно быть установлено через API-запрос.

Запросите URL WebSocket через CLI-инструмент (wscat) или Postman. Это подтвердит, что сервер может устанавливать соединения с другими клиентами (помимо браузеров), которые поддерживают WebSockets.

Рис. 13. Подключение к wss://polkadot.webapi.subscan.io/socket
  • Исследовательское тестирование: сервер должен отвечать правильными статус кодами.

Прежде всего, коды состояния вебсокетов отличаются от обычных HTTP-кодов.

Во-вторых, спецификация кодов статуса довольно расплывчата — некоторые коды могут быть отнесены к разным случаям. Например, авторизованный запрос может относиться как к 1008, так и к 1003.

Поэтому обработка ошибок сильно зависит от решений разработчиков (разумеется, как и в любом API), а тестирование сильно привязано к документации. Но если WebSocket API использует коды состояния HTTP — это определенно можно считать ошибкой.

А еще, получить код состояния из публичного вебсокет соединения который предполагает только отправку данных (например, wss://polkadot.webapi.subscan.io/socket), довольно сложно. Вариант вебсокета с возможностью отвечать на полученные сообщения является более «тестируемый»:

  • Попытка отправить пустое сообщение (здесь используется wcat, поскольку Postman не позволяет отправлять пустые сообщения на WebSockets):
Рис. 14. Сервер прервал соединение с кодом 1007
  • Попытка отправить сообщение неподдерживаемого типа:
Рис. 15. Сервер прервал соединение с кодом 1003

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

Тестирование бизнес-логики

Это самая важная часть тестирования API и самая разнообразная — все тест кейсы зависят от документации, дизайна тестов и поведения приложения.

Я приведу несколько примеров, основанных на документации CoinAPI.io Market Data WebSocket API.

  • Первый позитивный тест: сервер должен начать отправку ответных сообщений после получения корректного сообщения запроса.

После установки вебсокет-соединения необходимо отправить «сообщение приветствия«, которое содержит несколько необходимых параметров:

{"type": "hello", "apikey": "73034021-THIS-IS-SAMPLE-KEY", "heartbeat": false, "subscribe_data_type": ["trade"], "subscribe_filter_asset_id": ["DOT"]}
Рис. 16. сообщение «привет»
  • Тест тела ответа: сообщения ответа должны быть разборчивы, а значения ключей должны быть действительными.

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

{
  "time_exchange": "2022-07-11T13:37:30.2810000Z",
  "time_coinapi": "2022-07-11T13:37:30.4243323Z",
  "uuid": "4d4dfbb0-a69a-4ceb-a24a-810991907d2d",
  "price": 6.817,
  "size": 1.03845,
  "taker_side": "BUY",
  "symbol_id": "BINANCEFTS_PERP_DOT_USDT",
  "sequence": 71397,
  "type": "trade"
}

Расширенная проверка: значение symbol_id должно содержать данные в соответствии с фильтром subscribe_filter_asset_id (это означает, что строка "BINANCEFTS_PERP_DOT_USDT" должна включать "DOT").

  • Негативные тесты: сервер не должен отвечать на невалидное сообщение запроса.

Что делать, если сообщение запроса не соответствует требуемому формату? Что если тип не будет hello? apikey будет недействительным? subscribe_data_type будет находиться в недоступном диапазоне для бесплатного API-ключа? Сообщение не будет содержать необходимых параметров? и т.д.

Рис. 17-20. Различные негативные сценарии

Остальные кейсы необходимо проверять в соответствии с вашей статегией тестирования.

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

Дополнительные материалы:

🔥 Какой была ваша первая зарплата в QA и как вы искали первую работу? 

Мега обсуждение в нашем телеграм-канале о поиске первой работы. Обмен опытом и мнения.

Читать в телеграм

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *