Одним из наиболее распространенных инструментов для тестирования REST-сервисов на данный момент (на ряду, пожалуй, с Postman’ом), является утилита под названием SoapUI. Как следует из её названия, основное её предназначение - это тестирование (либо простое взаимодействие) веб-сервисов, работающих по протоколу SOAP. Однако, инструмент также годится и для операций с REST-сервисами. Как инструмент тестирования SoapUI подходит как для функциональных, так и для нагрузочных тестов, рассмотрением которых мы в сегодняшней статье и займемся.
Способности SoapUI в области эмуляции нагрузки не отличаются каким-либо богатством. Для всеобъемлящего тестирования не достает возможности контролировать порядок исполнения шагов и в целом то что относится к логике исполнения (циклы, условные ветвления, и т.д.), однако для проверки приложения на соответствие базовым требованиям по времени отклика и корректности ответа - вполне подойдет. Для остальных целей существует JMeter.
Итак, мы почти готовы начать. Осталось определиться с одной незначительной деталью. А что мы, собственно говоря, будем тестировать?
Описание примера
В примере мы подготовим наш собственный REST-сервис. У сервиса будет три ендпоинта. Первый всегда будет возвращать корректный результат. Второй будет возвращать ошибку в половине случаев (для демонстрационных целей мы будем выбрасывать ошибку намеренно). Третий - в трети случаев.
Для этого специально подготовленного сервиса мы создадим проект в SoapUI где реализуем функциональные тесты для нашего API, и в дальнейшем интегрируем их в нагрузочный сценарий.
Реализуем демонстрационный REST-сервис
Сервис мы напишем на языке Python с использованием библиотеки Flask. Этот выбор был сделан из-за простоты, быстроты и наглядности шагов, необходимых для реализации такого сервера. Однако, если вы никогда не работали с Python, то, скорее всего, вам придется выполнить нехитрые подготовительные процедуры:
-
Скачать и установить версию Python для вашей операционной системы. Если вы пользуетесь операционной системой Linux, то, скорее всего, у вас уже всё установлено. Проверить можно командой
python
. Если у вас Debian или Ubuntu, то вероятно, вам придется установить менеджер пакетовpip
, при помощи командыsudo apt install python-pip
-
Установить Flask командой
pip install -U flask
После того, как подготовительные процедуры завершены, мы можем приступить к написанию нашего тестового сервера. Ниже представлен код сервиса. Вам надо скопировать его к себе в файл на жёстком диске (например - demoservice.py
).
from flask import Flask from flask import Response from random import choice app = Flask(__name__) luck = "You're lucky now.." bad_luck = "Bad luck.." @app.route('/') def wec(): return 'WebElement.click!' @app.route('/half_error') def half_error(): if choice([True, False]): return Response(bad_luck, status=500) else: return Response(luck, status=200) @app.route('/third_error') def third_error(): if choice([True, False, False]): return Response(bad_luck, status=500) else: return Response(luck, status=200) if __name__ == '__main__': app.run(host='0.0.0.0', port='9090')
При условии что, ваш код был сохранен в файл demoservice.py
, запустить наш тестовый сервис можно теперь командой python demoservice.py
.
В принципе, код получился весьма самодокументированным. Поясню лишь некоторые моменты.
-
if choice([True, False])
иif choice([True, False, False])
- такая конструкция используется для случайной выборки из имеющегося списка. В первом случае, мы получим положительный результат с вероятностью 1/2, а во втором - с вероятностью 1/3. -
app.run(host='0.0.0.0', port='9090')
- означает что мы разрешаем обращения ото всех хостов сети, а также, что наш сервис будет висеть на порту9090
Создаём проект в SoapUI
Перед началом описания проекта стоит отметить, что в моем случае я буду использовать утилиту SoapUI версии 5.5.0
для операционной системы Linux. Тем не менее пример будет валиден и для остальных сборок утилиты.
При создании и отладке проекта желательно иметь наш демонстрационный сервер запущенным.
Итак, открываем SoapUI и нажимаем кнопку "REST" ("Создать новый REST проект"). В поле URL указываем наш базовый ендпоинт и не забываем указать номер порта, на котором у нас всё будет запускаться: http://localhost:9090/
.
Создав проект, переименуйте его во что-то осмысленное (например в WebElement.Click) и сохраните проект на жёстком диске. К этому моменту у нас появилось описание GET-запроса к нашему базовому адресу, который по задумке никогда не возвращает ошибку.

Если к этому моменту наш сервер запущен, мы можем выполнить запрос из SoapUI и убедиться, что мы получаем от него корректный отклик.
Добавляем два оставшихся ресурса. Кликаем правой кнопки мыши на узле сервиса (сразу под именем нашего проекта) и выбираем New Resource
. В первом случае добавляем ресурс /half_error
, а во втором - /third_error
. Каждый такой ресурс содержит в себе по экземпляру GET-запросов, сгенерированных по умолчанию. Их мы будем использовать в дальнейшем. Проверяем работоспособность ручным запусков запросов (рекомендую проверять результат во вкладке raw
- там будет видно и тело ответа и код ответа, который для второго и третьего ресурса иногда будет неуспешным).
Добавляем тестовые шаги
Перед тем как сформировать нагрузочный тест, нам необходимо описать функциональный сценарий, который мы в дальнейшем используем как базу для нагрузки. Выполняем следующую последовательность шагов:
-
Кликаем правой кнопкой на узел проекта и выбираем
New TestSuite
. Указываем какое-то осмысленное имя для нашего тестового набора. Например -WebElement.Click Test Suite
. -
Опять кликаем правой кнопкой, но уже только что созданный узел тестового набора и выбираем
New TestCase
. Устанавливаем имя узла вWEC Load Scenario
. -
Раскройте созданный узел тест кейса. В нем должны находиться несколько категорий. В том числе и
Test Steps
. Перетащите мышкой сгенерированные реквесты в эту категорию один за другим. При перетаскивании SoapUI предложит вам дать имя создаваемым шагам. Рекомендую дать шагам некие осмысленные имена. Например шаг, запрашивающий ресурс/
мог бы называтьсяAlways get OK
, шаг для ресурса/half_error
реквест мог бы называтьсяGet OK at half time
, а для ресурса/third_error
шаг мог бы называтьсяGet OK at two third times
. -
На данном этапе наши шаги не проверяются на соответствие результата ожидаемому значению. Но если мы говорим о тесте, неотъемлемым атрибутом шага должна быть проверка результата. Поэтому, двойным щелчком по узлу шага мы открываем шаг на редактирование и ищем внизу открывшегося модального окна слово "Assertions". Если нажать на эту кнопку откроется секция настройки проверок результатов. Нажимаем "+", находящийся в верхней части открывшейся секции. В левой части диалога выбираем "Compliance, Stauts and Standards", а в правой выбираем "Valid HTTP status codes" и нажимаем "Add". В поле валидных статусов пишем "200" и нажимаем [OK]. Повторяем операцию для каждого шага нашего теста.
-
[Опционально] Последним пунктом нам надо отсортировать шаги по вероятности возникновения ошибки (это опциональный шаг, который призван повысить репрезентативность результата). Дело в том, что каждый наш шаг подразумевает возникновение "ошибки" с демонстрационными целями. И каждый шаг выдает "ошибку" с разной вероятностью: первый - с нулевой, второй с половинной и третий с вероятностью одна третья. Кроме того, в том случае если SoapUI получает ошибочный ответ на один из шагов теста, то остальные шаги уже не выполняются, а тест помечается неуспешным. Итак, отсортируем (выбираем шаг и используем сочетание клавиш Ctrl+Up/Down для перемещения шага вверх либо вниз) шаги следующим образом:
-
Always get OK
-
Get OK at half time
-
Get OK at two third times
-
На данном этапе у нас готов функциональный тест. Мы можем открыть окно запуска теста двойным щелчком по узлу "Test Steps" и попробовать позапускать его.
Создаем нагрузочный тест
Дело за малым. Осталось добавить экземпляр нагрузочного теста с настройками нагрузки, а также проверкой временных характеристик ответов от нашего сервиса. Щелкните правой кнопкой мыши на узле Load Tests и выберите New LoadTest
. Дайте тесту какое-либо осмысленное имя, например Simple Load Test
.
Вы увидите модальное окно настройки нагрузочного теста, которое одновременно является и окном, показывающим результаты теста. Порядок следования шагов будет соответствовать порядку указанном в узле Test Steps
. При том, если вы поменяете порядок в окне нагрузочного теста, порядок поменяется везде.

Оставим конфигурацию нагрузки, заданную по умолчанию (более подробно о поддерживаемых конфигурация можно прочитать в официальной документации SoapUI) и запустим наш тест. Обратите внимание на значение в графе cnt
для первого шага. Оно говорит об общем количестве запусков, которые SoapUI произвел в соответствие с текущей конфигурацией нагрузочного теста. Первый шаг (ожидаемо) завершился без функциональных ошибок для всех запущенных экземпляров нашего теста, поэтому во втором шаге значение cnt
осталось неизменным.

Также выглядят ожидаемыми значения в графе err
для всех шагов. Для первого шага - это ноль, для второго - примерно половина от cnt
первого/второго шагов, а для третьего - треть от cnt
третьего шага.
Проверки количественных характеристик отклика
Те ошибки, которыми мы оперировали до сих пор относятся к разряду функциональных. Это означает, что в реальной среде на сервере бы возникла ошибка логики и он вернул бы что-то отличное от того, что мы считаем успешным ответом. В нагрузочных тестах SoapUI мы может также проверять то, насколько количество ошибок, время отклика и некоторые другие характеристики соответствуют ожидаемым значениям.
В окне конфигурации нагрузочного теста ищем внизу кнопку "LoadTest Assertions", нажимаем ее, а затем нажимаем зеленый "+" в верхней части открывшейся секции. Выбираем в появившемся окне "Max Errors" и жмем [OK].
Более подробно с возможностями проверок количественных характеристик ответов в нагрузочных тестах можно ознакомиться в официальной документации SoapUI. В нашем примере мы будем использовать метрику "Максимальное количество ошибок на шаге". Целевое значение для неё может устанавливаться как в абсолютном (количество ошибок), так и в относительном (доля ошибочных ответов в общем количестве запусков) формате. Для примера возьмем наш шаг который "падает" в половине случаев и укажем значение
0.5
(при достижении или превышении значения, тест будет считаться неуспешным).
Указываем значение 0.5
в графе Max Relative Errors
и 2500
в графе Max Absolute Errors
. В поле Test Step
выбираем значение Get OK at half time
. Сохраняем нашу проверку. Также для демонстрационных целей подправим немного конфигурацию запуска нашего нагрузочного сценария. В поле Limit
укажем значение 5000
, а в соседнем поле размерностей выберем Total Runs
. Запустим и проверим что получилось.

Как мы можем убедиться, тест остановился не дойдя до конца, как только текущий показатель доли ошибочных ответов перевалил за половину от общего количества запущенных к данному моменту "вторых" шагов.
Итак, мы научились создавать, конфигурировать и запускать нагрузочные тесты в SoapUI. Кроме того, пример демонстрационного сервиса, написанного на языке Python также выглядит весьма полезным и может найти применение в решении повседневных тестовых задач (например таких как создание простейших заглушек в вашей тестовой среде). В статье я покрыл основную часть возможностей по написанию нагрузочных сценариев, не затронув тем не менее такие важные моменты как использование groovy-скриптов и описание различных видов поддерживаемых стратегий нагрузки. Всё это помогает сделать тесты более гибкими (особенно groovy-скрипты), но также делает статью информационно-перегруженной. Я коснусь этих моментов в одном из следующих постов.
Остались вопросы? Задавайте их тут. Я постараюсь дополнить статью опираясь на ваши замечания.