🔥 Важное для QA-специалистов! 🔥
В QaRocks ты найдешь туториалы, задачи и полезные книги, которых нет в открытом доступе. Уже более 15.000 подписчиков – будь среди нас! Заходи к нам в телеграм канал QaRocks
Перевод статьи «How to Manually Test WebSocket APIs».
Если вы когда-либо тестировали HTTP API, то не столкнетесь с большими трудностями при тестировании двунаправленных сообщений. Однако есть несколько особенностей, присущих WebSockets, которые следует принять во внимание перед началом тестирования.
Теория
WebSocket — это постоянное соединение между клиентом и сервером. WebSockets обеспечивают двунаправленный канал связи (позволяет осуществлять связь в обоих направлениях одновременно) через одно соединение TCP/IP.
Благодаря соединению WebSocket связь между клиентом и сервером может происходить в режиме реального времени (в отличие от HTTP с потерями времени на каждый запрос/ответ), подобно UDP, но с надежностью TCP. Поэтому он широко используется в чатах, играх и браузерных приложениях фондового рынка.
WebSocket начинается с установления соединения (handshake), за которым следует основной обмен сообщениями:

Соединение вебсокет устанавливается путем обновления 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: upgradeUpgrade: websocketSec-WebSocket-Accept: key— сообщает, что сервер готов инициировать WebSocket-соединение.
В реальной жизни handshake выглядит следующим образом (в следующих примерах я буду использовать запросы на сайте Subscan.io):

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

Как только обе стороны подтвердят, что соединение должно быть закрыто, TCP-соединение будет разорвано.
Дополнительные материалы:
- RFC 6455 — Протокол WebSocket
- Механизм обновления протокола
- Как работают WebSockets
- Простое объяснение того, что такое WebSocket
- WebSockets — концептуальное погружение
- Будущее веб-программ — это HTML-over-WebSockets
Инструменты
Браузеры
Как следует из документации, вебсокеты предназначены для браузерных приложений, которым требуется двусторонняя связь с серверами. Таким образом, все современные браузеры поддерживают вебсокеты.

Вы можете увидеть все вебсокет соединения в 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();

В консоли браузера удобно сделать смоук тестирование, чтобы проверить, что соединение вообще можно установить.
Дополнительные материалы:
- WebSocket API
- Тестирование WebSockets для начинающих
- Как протестировать соединение WebSocket прямо в браузере
Wscat
Любители CLI будут разочарованы ограниченным набором инструментов для работы с WebSockets из терминала (к сожалению, даже libcurl не поддерживает WebSockets). Фактически, есть только один пригодный для использования CLI-инструмент — wscat.
Он устанавливается как npm пакет:
npm install -g wscat
И сразу же готов к работе:
wscat -c 'wss://polkadot.webapi.subscan.io/socket'

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

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

На данный момент в Postman нет вкладки «Тесты» для автоматизации тестов, как в интерфейсе HTTP-запросов. Таким образом, тестирование вебсокетов осуществляется вручную. Описание остальных возможностей выходит за рамки этой статьи, к тому же документация очень подробная.
Дополнительные материалы:
Практика
WebSocket API — это API, поэтому к WebSockets можно применять все те же стратегии тестирования, что и при тестировании REST API. Это значит, что основные проверки не будут сильно отличаться от обычного тестирования HTTP API:
- Проверьте правильность методов и кодов состояния;
- Проверьте полезную нагрузку запроса и ответа;
- Проверьте нефункциональные требования: время отклика, производительность, безопасность и т. д.
Кроме того, процесс функционального тестирования можно разделить на две основные части:
- Проверка правильности реализации протокола;
- Тестирование бизнес-логики.
Отказ от ответственности: для демонстрации выполнения различных примеров я использовал разные инструменты. Нет никаких особых причин, почему я использую один инструмент вместо другого, кроме презентабельности. Окончательный выбор инструмента тестирования остается за вами.
Проверка правильности реализации
Как было описано в теоретической части статьи, начальным этапом подключения по вебсокету является handshake, и все доступные инструменты выполняют его автоматически. Это очень удобно, но не оставляет места для ручного тестирования, поскольку привычные HTTP-инструменты не работают с WebSockets — даже сами браузеры не делают WebSocket-запросы за пределами исходной веб-страницы:

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


- Негативный тест: соединение не должно устанавливаться по недопустимому протоколу.
Запрашивайте URL вебсокета как обычный HTTPS-запрос вместо WSS.

Другой стороной этого случая может быть попытка установить незащищенное соединение. Существует два типа протокола WebSocket:
- ws подключается по протоколу HTTP;
- wss подключается только по протоколу HTTPS (защищенный).

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

- Исследовательское тестирование: сервер должен отвечать правильными статус кодами.
Прежде всего, коды состояния вебсокетов отличаются от обычных HTTP-кодов.
Во-вторых, спецификация кодов статуса довольно расплывчата — некоторые коды могут быть отнесены к разным случаям. Например, авторизованный запрос может относиться как к 1008, так и к 1003.
Поэтому обработка ошибок сильно зависит от решений разработчиков (разумеется, как и в любом API), а тестирование сильно привязано к документации. Но если WebSocket API использует коды состояния HTTP — это определенно можно считать ошибкой.
А еще, получить код состояния из публичного вебсокет соединения который предполагает только отправку данных (например, wss://polkadot.webapi.subscan.io/socket), довольно сложно. Вариант вебсокета с возможностью отвечать на полученные сообщения является более «тестируемый»:
- Попытка отправить пустое сообщение (здесь используется wcat, поскольку Postman не позволяет отправлять пустые сообщения на WebSockets):

- Попытка отправить сообщение неподдерживаемого типа:

Вы можете придумать еще больше тест кейсов, но эти проверки уже больше относятся к бизнес-логике.
Тестирование бизнес-логики
Это самая важная часть тестирования 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"]}

- Тест тела ответа: сообщения ответа должны быть разборчивы, а значения ключей должны быть действительными.
Возьмем случайное сообщение ответа — оно имеет формат 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-ключа? Сообщение не будет содержать необходимых параметров? и т.д.




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