Инициализация 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/


Интересные статьи

Интересные статьи

В данной статье мы рассмотрим процесс создания формы на базе JavaScript и включения ее в экран создания запроса в JIRA.Это может быть полезно, если вы хотите получить большую гибкость, чем предоставля...
Вышла общедоступная версия Java 19. В этот релиз попало более двух тысяч закрытых задач и 7 JEP'ов. Release Notes можно посмотреть здесь. Изменения API – здесь.
Обработка исключений в Java в функциональном стиле. Часть 2. В предыдущей статье была рассмотрена функциональная обработка исключений с помощью интерфейса Try<T>. Статья вызвала определенный ин...
Дайджест новостей и полезных статей из мира фронтенд-разработки за неделю 4–10 июля.
Перевод статьи подготовлен специально для студентов курса «Разработчик на Spring Framework». Давайте создадим простейшее Spring Boot-приложение, которое будет запускаться в кластере Kube...