
О чём статья?
Если вам необходимо автоматизировать тестирование веб-сокетов, то эта статья будет для вас полезна. В ней я поделюсь своим опытом "прикручивания" библиотеки Spring Boot Starter Websocket к проекту автотестов на Java.
По данной теме в интернете можно найти много гайдов, но во всех них приводятся примеры клиентов на JavaScript. Поэтому мне показалось полезным собрать в одном месте необходимые шаги для создания клиента на Java.
Эта статья - своего рода инструкция для быстрого запуска WebSocket-клиента в вашем проекте. Поэтому я намеренно опущу описание ряда деталей (например, что такое веб-сокеты и STOMP-протокол) и подробное описание интерфейсов библиотеки. Вы сможете узнать подробнее о терминах в других источниках, таких как эта статья, и обратиться к документации пакета.
Предисловие
Пара слов о тестируемом мной продукте: это клиентское web-приложение, которое взаимодействует с бэком через http- и ws-протоколы.
Немного о самих автотестах: проект на Java, используется сборщик Maven, тестовый фреймворк TestNG + чистый Selenium, шаблон проектирования тестов PageObject.
Для контроля качества продукта в тестах недостаточно пройти какие-либо пользовательские сценарии от точки А до точки В. Требуется также проверить, что отображаемые на фронте данные соответствуют бизнес-логике и полученным сообщениям от сервера. Для этой цели в автотестах для работы с API обычно используют RestAssured, но данная библиотека не позволяет работать с веб-сокетами. Поэтому мы обращаемся за помощью к Spring Boot Starter WebSocket.
Почему Spring Boot Starter Websocket, ведь есть иные библиотеки для работы с веб-сокетами на Java (например, Java WebSocket)?
1. В интернете по данной библиотеке можно найти больше информации: как минимум, есть документация.
2. В Java WebSocket есть ряд уязвимостей, связанных с зависимостями (например, уязвимость Denial of Service).

Итак, с помощью библиотеки Spring Boot Starter Websocket в проекте автотестов мы создадим клиента. Он будет взаимодействовать с веб-сокетом и выполнять следующие функции:
Подключение к WebSocket (кстати, под капотом библиотеки реализован handshake, поэтому нам не нужно отдельно продумывать update http-запроса до веб-сокета).
Подписка на топик, получение всех сообщений от сервера по веб-сокету.
Отправка сообщений на сервер по открытому веб-сокету.
Отписка от топика.
Закрытие соединения по веб-сокету.
С таким клиентом мы можем получать сообщение от сервера, обрабатывать его и сравнивать полученные данные с отображаемой информацией на фронте.
Step by step...
1. Для создания клиента сначала добавляем библиотеку в проект. Указываем зависимость в pom:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> <version>2.7.17</version> </dependency>
2. Создаём два класса:
a) WSClient. В нём будут инициализироваться классы библиотеки, и будет вызываться метод подключения к веб-сокету.
b) StompSessionHandler. Класс содержит описание действий клиента после подключения к веб-сокету.
3. Вызываем метод firstWSClient в самих тестах.
Далее привожу примеры кода для реализации клиента.
Еще оставлю ссылку на примеры из документации.
WSClient
public class WSClient { public void firstWSClient() { // Инициализируем классы библиотеки WebSocketClient webSocketClient = new StandardWebSocketClient(); WebSocketStompClient stompClient = new WebSocketStompClient(webSocketClient); stompClient.setMessageConverter(new MappingJackson2MessageConverter()); StompSessionHandler myStompSessionHandler = new StompSessionHandler(); // Определяем заголовки при обновлении http до ws (handshake) WebSocketHttpHeaders websocketheaders = new WebSocketHttpHeaders(); // Если требуется передавать авторизационные данные (токен или пароль) websocketheaders.set("Content-Type", "text/css;charset=UTF-8"); // Определяем заголовок сообщений, передаваемых по веб-сокету StompHeaders stompHeaders = new StompHeaders(); // Например, указываем топик, на который хотим подписаться stompHeaders.set(StompHeaders.DESTINATION, "topic/message"); // Указываем URL веб-сокета, к которому требуется подключиться String URL = "http://localhost:8080/"; // Подключение к веб-сокету ListenableFuture<StompSession> sessionAsync = stompClient.connect(URL, websocketheaders, stompHeaders, myStompSessionHandler); StompSession stompSession = sessionAsync.get(5, TimeUnit.SECONDS); // Подписываемся на топик stompSession.subscribe(stompHeaders, myStompSessionHandler); // Оправка сообщения по веб-сокету на сервер stompSession.send(stompHeaders, "Hello, World!"); } }
Для работы клиента нужно определить и передать заголовки для http-запроса-«рукопожатия», чтобы открыть веб-сокет. Скорее всего, вам потребуется передать авторизационные данные, например, токен (строки 10-13).
Также определите топик, на который вам нужно подписаться. Это можно выяснить самому, посмотрев подключение через DevTools браузера на вашем фронте. Либо спросите своих backend-разработчиков.
Топик передаём в заголовке сообщения по веб-сокету, на этапе подписки. Само наполнение хедера отражено в строках 15-18.
Далее в примере происходит подключение, подписка и отправка сообщения (строки 23-31). Обращу внимание, что методы subscribe, send перегружены и могут использоваться с другими аргументами. Например, можно не использовать stompHeaders при вызове subscribe, а только передать топик строкой (destination). С методом send такая же картина.
StompSessionHandler
public class StompSessionHandler extends StompSessionHandlerAdapter { // Описываем действия с подключением к веб-сокету // В этом примере выводим в консоль, что подключение есть @Override public void afterConnected(StompSession session, StompHeaders connectedHeaders) { System.out.println("Opening websocket..."); System.out.println("Session is connected: " + session.isConnected() + "\n"); } // Обработчик сообщений из веб-сокета @Override public void handleFrame(StompHeaders headers, Object payload) { String json = new String((byte[]) payload); System.out.println("Received json:\n" + json + "\n"); } }
В данном примере метод afterConnected выведет в консоль информацию об успешном подключении к веб-сокету.
Метод handleFrame выводит в консоль сообщения из веб-сокета. С помощью него также можно организовать маппинг сообщений для тестов, где можно будет сравнить полученное по веб-сокету сообщение с данными, собранными через Selenium на фронте.
Инициализация клиента в тестах
@Test(description = "Получение данных по веб-сокету") public void getWSTestData(){ WSClient wsClient = new WSClient(); wsClient.firstWSClient(); }
Добавляем строки инициализации класса WSClient и вызов метода firstWSClient в нужных тестах, где требуется работа с веб-сокетом.
Заключение
Надеюсь, данная инструкция поможет сэкономить время при создании клиента по работе с WebSocket’ами в ваших проектах по автотестированию на Java. Пусть уровень качества тестируемых продуктов становится только выше!
