WSTester – JS библиотека для тестирования веб-сервисов с ВебСокетами
Добрый день, Хабрасообщество! Как и большинству айтишников, мне нравится создавать что-то новое, классное, нечто способное как-то повлиять на мир или хотя бы принести небольшую пользу другим людям. Надеюсь, что описываемый далее инструмент для тестирования онлайн систем с ВебСокетами как раз такая вещь.
Предыстория
Большинство идей рождаются в результате активной и разнообразной работы, и данная идея не исключение. Для тестирования своей кросс-платформенной игры мне пришлось писать много тестов. Для iOS в среде Xcode предоставляется удобнейший встроенный функционал, (алгоритмы в Java под Android я просто переписывал с Obj-C, решил обойтись без юнит-тестов). На серваке многие алгоритмы можно тестировать изнутри при его локальном запуске, а для проверки правильной обработки HTTP запросов можно легко написать скрипт на Python с библиотекой requests
.
Однако когда для взаимодействия клиентов-сервера пришлось добавить канал связи по WebSocket«ам, я не уделил его тестированию нужного внимания. В итоге, в игре не было возможности создать нового юзера через ВебСокеты, а приложение использовало именно их… Глядя на статистику я быстро заподозрил что-то неладное, но принял решительные действия лишь спустя месяц-другой.
Главной причиной появления этой ошибке в production«e было то, что для тестирования ВебСокетов не было видно простых путей — ведь в отличии от HTTP, где у каждого запроса есть ответ, в ВебСокетах можно отправить сколько угодно сообщений на сервер и не получить ответа вовсе; или же ничего не отправлять, зато получить любое количество различных сообщений.
Поискав в Интернете, я не нашёл каких-то рекомендаций по этой теме. Возможно я плохо искал, или возможно эта технология ещё слишком молодая, и для крупных проектов пишутся собственные системы для тестирования, а в малых всё делается вручную. Однако я увидел небольшую пустоту в мировом программном континууме и поспешил её закрыть.
В результате получились JavaScript библиотека WebSocket Testing Engine (вкратце WSTester) и веб-страница для работы с ней через готовый GUI, который принимает JS файл с кодом тестов. Все исходники доступны на ГитХабе.
Принцип работы
WSTester работает как конечный автомат — на вход подаются потоки выполнения, они исполняются независимо и последовательно, их можно считать за юнит-тесты. Каждый поток выполнения — это массив или словарь JavaScript, он состоит из юнитов, и в каждый момент времени существует лишь один текущий юнит.
Первым в потоке вызывается юнит с индексом 1, последующие могут быть любыми. Если поток это массив, то следующим считается юнит с индексом равным текущему + 1, но можно и поменять индекс следующего юнита. Если поток является словарём, то в нём всегда нужно самостоятельно указывать индекс следующего юнита.
Структура объекта юнита такова:
{
name: string,
enter: function () {},
task: function (ws, ref) {},
condition: function (data) {},
key: string,
val: any type,
finalise: function (ws) {},
}
Поле name
используется для вывода информации по юниту, enter
и task
применяются при переходе к новому текущему юниту, а condition
, key
, val
и finalise
при получении нового сообщения.
Успешно выполненным юнит считается тогда, когда полученное сообщение удовлетворит одному из условий:
- Если указана функция
condition
, то юнит завершается успешно, если функция с аргументом полученным сообщением вернётtrue
или индекс следующего юнита. - Если указаны
key
иval
, то юнит завершается успешно, если полученное сообщение имеет поле с названием равнымkey
и значением этого поля равным значениюval
. Кстати, еслиval
является массивом, то все его значения будут проверены по отдельности. - Если указан
key
, но неval
, то юнит завершается успешно, если полученное сообщение имеет поле с названием равнымkey
.
Если же с момента запуска юнита не было получено подходящих сообщений в течение заданного времени, то текущие юнит и поток считаются проваленными.
Описанной выше информации достаточно для написания тестов, которые можно запускать через готовый интерфейс WSTester. Значительно больше и подробней о принципах работы можно узнать тут и ещё здесь.
В интерфейсе можно менять разные настройки: адрес WebSockets сервера, время ожидания подходящего сообщения до провала юнита, нужно ли создавать новые подключения для каждого потока, время между юнитами. Эти же параметры можно задать в JS файле тестов для максимальной автоматизации. Также, GUI может принимать файлы тестов по указанному URL или напрямую с компьютера.
При использовании самой JS библиотеки помимо перечисленных опций можно задать функцию вывода лога, функцию, вызывающуюся после переподключения соединения, и функцию, вызывающуюся после исполнения всех тестов с количествами успешных и проваленных потоков.
Примеры использования
Основной функционал разрабатывался в рамках проекта вышеупомянутой игры, как аналог тестам по HTTP запросам, однако впоследствии был проверен и расширен в работе с несколькими другими сервисами. Ниже указано несколько тестов, описание и ссылки на файлы и сервисы.
- data_toy.js — модификация реальных тестов логической игры TacticToy. Содержит 4 потока, 16 юнитов. Запустить файл.
Фичи:condition
; поток как словарь; пропуск юнитов с использованиемcondition
иref.next
. - data_gdax.js — образец теста для GDAX WebSocket API. Содержит 3 потока, 3 юнита. Запустить файл.
Фичи:val
как массив;args.split
. - data_block.js — образец теста для Blockchain transaction WebSocket API. Содержит 1 поток и 3 юнита. Запустить файл.
Фичи:finalise
. - data_ether.js — образец теста для The Etherscan Block Explorer WebSocket API. Содержит 2 потока и 6 юнитов. Запустить файл.
Фичи: поток как словарь;ref.next
;args.split
.
Стоит отметить, что хотя данные тесты и содержат весь функционал WS Testing Engine, они всё же не достигают каких-либо пределов, оставляя огромный простор для фантазии: можно определить и использовать внешние переменные, функции, объекты и работать с ними в юнитах, можно сделать циклические переходы между юнитами по навороченным правилам, и т.д. Язык JavaScript к таким вещам очень располагает.
P.S.
- Конечно, упомянутую ошибку можно было выявить и другими способами, но суть рассказа не в этом.
- Почему JavaScript? Потому что это достаточно мощный и в то же время легковесный кросс-платформенный язык, в котором ВебСокеты поддерживаются из коробки, и ещё к нему можно легко добавить интерфейс (HTML+CSS).
- Я стараюсь быть точным в своих высказываниях и используемых терминах, но если кто-то заметит ошибки, прошу не ругать, но доброжелательно прокомментировать.
- К сожалению, мне мало удалось найти открытых API на ВебСокетах, где не нужна предварительная регистрация. Если у Вас есть предложения для расширения списка — смело предлагайте свои варианты.
Код библиотеки и прочие файлы на ГитХабе.