Инициализация WebSocket-клиента в автотестах на Java cо Spring Boot Starter WebSocket

—

от автора

О чём статья?

Если вам необходимо автоматизировать тестирование веб-сокетов, то эта статья будет для вас полезна. В ней я поделюсь своим опытом «прикручивания» библиотеки 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). 

Рис. 1 Уязвимости Java WebSocket

Рис. 1 Уязвимости Java WebSocket

Итак, с помощью библиотеки Spring Boot Starter Websocket в проекте автотестов мы создадим клиента. Он будет взаимодействовать с веб-сокетом и выполнять следующие функции:

  1. Подключение к WebSocket (кстати, под капотом библиотеки реализован handshake, поэтому нам не нужно отдельно продумывать update http-запроса до веб-сокета).

  2. Подписка на топик, получение всех сообщений от сервера по веб-сокету.

  3. Отправка сообщений на сервер по открытому веб-сокету.

  4. Отписка от топика.

  5. Закрытие соединения по веб-сокету. 

С таким клиентом мы можем получать сообщение от сервера, обрабатывать его и сравнивать полученные данные с отображаемой информацией на фронте.

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. Пусть уровень качества тестируемых продуктов становится только выше!


ссылка на оригинал статьи https://habr.com/ru/articles/773272/


Комментарии

Добавить комментарий

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