Всем привет!

В первой части статьи я рассказала про SoapUI в целом, а также работу с ним через командную строку, Docker и Python. В этой части мы подробно рассмотрим структуру XML‑файла SoapUI‑проекта: основные теги и нюансы работы с ними.

Навигация:

  1. Общая структура проекта

  2. Custom Properties

  3. Interface

  4. testSuite

  5. testCase

  6. testStep

  7. loadTest

  8. securityTest

  9. mockService

  10. mockOperation

  11. restMockAction

  12. SoapUI и Groovy

  13. Заключение

Будет полезно всем, кто хочет работать с файлом проекта не только через графический интерфейс, но и при автоматической генерации файлов или копировании.

После погружения в SoapUI
После погружения в SoapUI

Напомню, что статья написана по мотивам автоматизации запуска юнит‑тестов (UT, unit‑тесты). Для ее выполнения мне нужно было отрефакторить более 70 проектов. Вручную делать этого не хотелось, поэтому я стала оптимизировать отдельные этапы.

Общая структура проекта 

Проект в SoapUI — это файл с расширением XML. Он состоит из корневого тега soapui‑project и дочерних ему сущностей, которые описывают тесты и их окружение.

Если вы собрались вручную что‑то исправлять в исходнике проекта, то предварительно закройте его в SoapUI, либо закройте само приложение. В первом случае нужно будет перезагрузить проект (Reload Project или F5). Во втором — приложение все сделает за вас.

Будьте аккуратнее с форматированием исходника в IDE, так как теги с большим количеством текста, например, groovy, могут быть перенесены некорректно (появится лишний перевод строки).

Упрощенно структура будет выглядеть следующим образом:

Упрощенная структура SoapUI-проекта
Упрощенная структура SoapUI-проекта

На скриншоте удалены все атрибуты и содержание тегов. Основной неймспейс — это «http://eviware.com/soapui/config», соответствующий ему префикс «con» есть у всех тегов в проекте. Для удобства в рамках статьи он опущен, т. е. в тексте указано «testStep», но в файле будет «<con:testStep>». Все значения атрибутов тегов в XML нужно указывать в двойных кавычках.

У многих тегов встречается атрибут id, при генерации XML его заполнять не обязательно — при первом открытии проекта через GUI пропущенные идентификаторы проставятся автоматически.

Атрибуты тега soapui-project

Атрибут

Описание

name

Название проекта, в GUI отображается в списке открытых проектов

activeEnvironment

resourceRoot

soapui‑version

Версия SoapUI, например, 5.7.0

abortOnError

Флаг «прерывать при получении ошибки или нет»

runType

Тип запуска: последовательный (SEQUENTIAL) или параллельный (PARALLELL)

На первом уровне дочерних тегов находятся:

  1. description — описание проекта

  2. settings — настройки (встречается во многих сущностях)

  3. interface — может быть несколько, wsdl‑ или wadl‑интерфейс

  4. testSuite — может быть несколько, содержит testCase

  5. mockService — может быть несколько, теги для REST‑ и SOAP‑mock отличаются

  6. properties — это CustomProperties у проекта, testSuite, testCase, testStep, mockService, mockResponse и т. д. Состоит из набора тегов property, которые, в свою очередь, состоят из name и value.

На уровне soapui-project тег settings появляется, когда настройки проекта не совпадают с настройками SoapUI. Например, если там не настроено кеширование WSDL-интерфейсов, а в проекте cashed = True.

Настройка кеширования WSDL на уровне приложения
Настройка кеширования WSDL на уровне приложения
Настройка кеширования WSDL на уровне проекта
Настройка кеширования WSDL на уровне проекта

В XML-файле:

<con:settings>
  <con:setting id="WsdlSettings@cache-wsdls">true</con:setting>
</con:settings>

Если глобальные или проектные настройки изменятся, то запись в XML-файле удалена не будет. Таким образом можно обеспечить одинаковую работу проекта на разных окружениях (например, у разных разработчиков).

Custom Properties

Custom properties (также пользовательские свойства, характеристики) — удобный инструмент для настройки. Этот тег встречается на разных уровнях проекта вплоть до Test Step и Mock Response. Доступ к ним осуществляется следующим образом:

${#<место хранения>#<название переменной>}

<vacationType>${#Project#VacationType}</vacationType>
<currentDate>${#TestCase#CurrentDateTime}</currentDate>

В наших проектах с unit‑тестами встречался хардкод значений пользовательских свойств. В большинстве случаев это уместно, но есть и исключения. Самое простое — даты. Если тестируемое приложение должно как‑то особенно их обрабатывать, например, проверять, входит ли она в разрешенный интервал, то в UT лучше использовать скрипты: они позволят решить проблему динамической генерации данных без участия человека.

Рассмотрим простой вариант установки даты начала и окончания. Напишем скрипт на Groovy:

import java.text.SimpleDateFormat;
 
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DATE, -14);
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.ms+03:00").format(cal.getTime());

Создадим Custom Property и вставим скрипт в графу value:

Отображение Groovy-скриптов в GUI
Отображение Groovy-скриптов в GUI

В XML‑файле код будет выглядеть следующим образом:

Отображение Groovy-скриптов в xml
Отображение Groovy-скриптов в xml

Поскольку файл не предназначен для редактирования человеком, то весь скрипт превращается в очень длинную строку. Что‑то простое можно описать таким образом, но для более сложных случаев лучше создать отдельный Test Step.

Возьмем похожий скрипт для получения даты и создадим Test Step с названием current_date. Его результат сохранится в локальное пользовательское свойство result.

Пример Groovy-скрипта с расчетом даты
Пример Groovy-скрипта с расчетом даты
Отображение результата выполнения Groovy-скрипта
Отображение результата выполнения Groovy-скрипта

Далее с помощью Test Step вида TransferProperty установим результат выполнения скрипта в curr_date:

Пример маппинга результата Groovy-скрипта в Custom Properties
Пример маппинга результата Groovy-скрипта в Custom Properties

В графе Source указывается название объекта‑источника переменной (в нашем случае, это название Test Step), в Property — название Custom Property (в примере это будет result). В Target: целевой объект и целевое пользовательское свойство. На скриншоте выше маппинг производится в TestSuite «GetBird» в его свойство curr_date.

Transfer Property проставляет результат выполнения скрипта в поле value у соответствующей Custom Property. Значение записывается в XML‑файл и хранится до тех пор, пока его не изменят вручную или запустив тесты. В рамках автозапуска SoapUI‑проекта этот подход гарантирует актуальность данных, а в GUI можно работать и не используя скрипты.

Custom Properties можно импортировать и экспортировать, а также задавать их значение через консоль. SoapUI выгружает свойства в файл в формате: PROPERTY_NAME=PROPERTY_VALUE.

При запуске через консоль применяются только те параметры, которые уже были в проекте, новые придется создавать отдельно. В GUI же подобных проблем нет, так как есть настройка «Create Missing»:

Пример импорта настроек из файла
Пример импорта настроек из файла

Interface

Одна из возможных причин большого объема исходного файла кроется в теге interface. Раньше я пробовала открывать XML‑файл, но, увидев несколько десятков тысяч строк, закрывала редактор XML и возвращалась страдать в GUI.

SoapUI поддерживает два вида интерфейсов: WSDL для SOAP и его аналог WADL для REST. С точки зрения SoapUI работа с ними мало чем отличается. При импорте интерфейса в проект для каждой точки входа (bindings) создается свой объект interface. Также там сохраняется исходный код WSDL.

В XML‑файле тег имеет несколько атрибутов. В GUI они отображаются в виде Service Properties для WADL и Interface Properties для WSDL.

Настройки для WADL-интерфейса
Настройки для WADL-интерфейса
Атрибуты тега interface для разных интерфейсов

Атрибут

Наличие в WSDL

Наличие в WADL

Комментарий

wsaVersion

+

-

по умолчанию, "None" 

name

Атрибут name тега binding из WSDL

Имя проекта

type

type="wsdl"

type="rest"

указывает на тип интерфейса

bindingName

Название биндинга с неймспейсом (targetNamespace из wsdl)

-

Пример: bindingName="{http://www.bercut.com/bestbirdinterface}TheBestBirdIsBercutPortBinding"

soapVersion

"1_1"

-

версия SOAP-протокола

anonymous

"optional"

-

definition

+

-

путь, по которому хранится wsdl, можно указывать с помощью переменных, например, «${#Project#WSDL_TheBestBirdIsBercut}»; путь к файлу на локальном компьютере; адрес хоста, на котором размещен WSDL интерфейс

xsi:type

"con:WsdlInterface"

"con:RestService"

еще раз обозначаем тип интерфейса, но уже в терминах исходного  кода SoapUI

xmlns:xsi

+

+

wadlVersion

-

"http://research.sun.com/wadl/2006/10"

basePath

-

"/"

definitionUrl

-

+

Путь до проекта wadl

Если вы редактируете Interface Properties через GUI, то проверяйте сохранение данных. Так, после завершения редактирования параметра Definition нужно снять выделение, кликнув на любое другое Interface Property или пустое поле в этом же разделе. Если вы переключитесь на другой интерфейс и окно Interface Properties закроется, то ваши изменения исчезнут.

Interface имеет несколько дочерних тегов, например, endpoints. Он содержит набор <endpoint> с перечислением адресов, по которым отправляется запрос. Можно указывать как переменными, так и константами.

<con:endpoint>http://localhost:8080</con:endpoint>
<con:endpoint>${#Project#BEST_MOCK_ENDPOINT}</con:endpoint>

В нашем случае отдельные сервисы и методы могли не меняться годами, и интерфейсы в SoapUI‑проектах устаревали. При попытке загрузить свежую версию возникали конфликты. Вручную решить их можно, но при автозапуске желательно минимизировать вероятность их появления.

Управление кэшем осуществляется через настройку Cache WSDLs. В GUI она выставляется на глобальном уровне для всех SoapUI‑проектов пользователя: Preferences → WSDL Settings → Cache WSDLs. Либо на уровне проекта Project Properties — Cache Definition. По умолчанию SoapUI сохраняет кэш интерфейсов в тег definitionCache.

Следующий дочерний тег — operation. Он доступен для WsdlInterface и описывает методы, которые реализует binding. Он используется по принципу «один метод — один тег». Атрибуты bindingOperationName, inputName и outputName заполняются согласно WSDL. Name обычно совпадает с bindingOperationName, type отображает ожидание ответа от операции: «Request‑Response» и «One‑Way». Атрибут action может быть пустой строкой или соответствовать bindingOperationName. Также можно устанавливать атрибуты receivesAttachments, sendsAttachments, anonymous.

При добавлении запросов (New Requests или Ctrl+N) появляется дочерний тег call, у которого, в свою очередь, есть теги settings, encoding (например, UTF-8, значение указывается без кавычек), endpoint, request с текстом запроса, который мы видим в окне с вызовом, credentials, jmsConfig и wsaConfig.

Если в проекте есть два интерфейса А и В, и у каждого их них есть операция с названием C, то при удалении интерфейса А будут также удалены Test Steps операции С интерфейса В.

Пример interface в XML-файле
<con:interface xsi:type="con:WsdlInterface" id="cebbcb47-0866-4ef2-abf8-a84765d58cf9" wsaVersion="NONE" name="SampleServiceSoapBinding" type="wsdl" bindingName="{http://www.soapui.org/sample/}SampleServiceSoapBinding" soapVersion="1_1" anonymous="optional" definition="file:/C:/user_name/SoapUI-Tutorials/SoapUI-Tutorials/WSDL-WADL/sample-service.wsdl" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <con:settings/>
        <con:endpoints>
            <con:endpoint>http://www.soapui.org/sample</con:endpoint>
        </con:endpoints>
        <con:operation id="ececa212-81d7-4852-b338-46265d6523e4" isOneWay="false" action="http://www.soapui.org/sample/buy" name="buy" bindingOperationName="buy" type="Request-Response" inputName="" receivesAttachments="false" sendsAttachments="false" anonymous="optional">
            <con:settings/>
            <con:call id="544622c1-da86-42f2-9a36-52b82da979e7" name="Request 1">
                <con:settings/>
                <con:encoding>UTF-8</con:encoding>
                <con:endpoint>http://www.soapui.org/sample</con:endpoint>
                <con:request><![CDATA[<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sam="http://www.soapui.org/sample/">\r
   <soapenv:Header/>\r
   <soapenv:Body>\r
      <sam:buy>\r
         <sessionid>?</sessionid>\r
         <buystring>?</buystring>\r
      </sam:buy>\r
   </soapenv:Body>\r
</soapenv:Envelope>]]></con:request>
                <con:wsaConfig mustUnderstand="NONE" version="200508" action="http://www.soapui.org/sample/buy"/>
            </con:call>
        </con:operation>
        <con:operation id="2e4fcc2f-4d66-4d86-8485-1b35e4ab2f28" isOneWay="false" action="http://www.soapui.org/sample/login" name="login" bindingOperationName="login" type="Request-Response" inputName="" receivesAttachments="false" sendsAttachments="false" anonymous="optional">
            <con:settings/>
            <con:call id="7d1bd3d2-bc31-4dd7-babe-8bf447077113" name="Request 1">
                <con:settings/>
                <con:encoding>UTF-8</con:encoding>
                <con:endpoint>http://www.soapui.org/sample</con:endpoint>
                <con:request><![CDATA[<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sam="http://www.soapui.org/sample/">\r
   <soapenv:Header/>\r
   <soapenv:Body>\r
      <sam:login>\r
         <username>?</username>\r
         <password>?</password>\r
      </sam:login>\r
   </soapenv:Body>\r
</soapenv:Envelope>]]></con:request>
                <con:wsaConfig mustUnderstand="NONE" version="200508" action="http://www.soapui.org/sample/login"/>
            </con:call>
        </con:operation>
 </con:interface>

Если вы генерируете проект с нуля или хотите добавить в существующий новый interface, то в XML достаточно будет перечислить operation с атрибутами. Можно указывать не все операции, а только необходимые. Проект корректно откроется и Test Steps с этими методами будут доступны для редактирования. Интерфейс можно будет обновить позже с помощью Add WSDL или Update Definition.

testSuite  

Test Suite — это верхний уровень организации тестов. Каждый такой объект хранится как отдельный тег testSuite.

Он имеет всего два атрибута — id и name, но могут встречаться дополнительные, например, disabled.

Первый дочерний тег — settings, затем идет runType — способ запуска тестов и properties. Также появляются setupScript и tearDownScript, значение которых описывается как значение тега, без кавычек и прочего. Обратите внимание, что отступы сохраняются в XML‑файле как есть.

Пример отступов в GUI
Пример отступов в GUI

В файле проекта код будет выглядеть вот так (оригинальные отступы сохранены):

<con:tearDownScript>чирик чирик
чирик
</con:tearDownScript>

Рассмотрим интерфейс редактирования TestSuite.

Интерфейс редактирования testSuite
Интерфейс редактирования TestSuite

Синим и красным квадратами обозначен выбор способа выполнения runType: SEQUENTIAL («последовательные») и PARALLEL («параллельные») соответственно. В XML‑файле значения записываются большими буквами, без кавычек. Setup Script и TearDown Script позволяют добавить Groovy‑код до и после выполнения Test Suite. В зеленом прямоугольнике выделены доступные для скрипта объекты исходного кода SoapUI, в котором можно получить более подробную информацию о доступных методах, переменных и т. д.

В ходе развития и рефакторинга наших unit‑тестов так сложилось, что мы абстрагировались от названий элементов и стали использовать цепочку Test Suite — Test Case — Test Step в качестве способа группировки. Таким образом у нас появились служебные Test Suite. Их удобно использовать для группировки Test Steps с SOAP‑запросами и другими полезными действиями. Чтобы они не влияли на общий прогон, их можно пометить как disabled. Эта настройка не мешает вызывать их из Groovy‑скриптов.

testCase

testCase — это дочерний тег testSuite. Это минимальный уровень, который можно запустить из Groovy‑скрипта. В дополнение к properties и settings, он содержит перечень тестовых шагов: testStep, loadTest, securityTest.

Окно в GUI для запуска TestCase с определенного шага
Окно в GUI для запуска TestCase с определенного шага

В редакторе TestCase можно создать новый шаг (строка со значками после TestSteps), запустить его, остановить или зациклить выполнение (иконка круга после красного квадрата остановки — на скриншоте эта настройка включена). Можно отметить функцию запуска тест‑кейса с определенного шага (правая кнопка мыши на нужном testStep → «Run from here»).

Значения полей description, Setup Script и TearDown Script сохраняются в соответствующих тегах: description, setupScript, tearDownScript, а заданные Custom Properties — в структуры properties.

TestCase Editor позволяет настраивать логирование: максимальное количество строк (Max Rows) и наполнение логов. Параметр Follow в testCase не сохраняется:

Окно настройки логирования
Окно настройки логирования
<con:settings>
    <con:setting id="HttpSettings@socket_timeout">34</con:setting>
    <con:setting id="com.eviware.soapui.impl.wsdl.panels.testcase.JTestRunLog$OptionsForm@max_rows">1000</con:setting>
    <con:setting id="com.eviware.soapui.impl.wsdl.panels.testcase.JTestRunLog$OptionsForm@errors_only">true</con:setting>
</con:settings>

Тег setting с id = HttpSettings@socket_timeout указывает на настройку Socket timeout в TestCase Options (TestCase Editor → значок шестеренки). Остальные параметры хранятся в атрибутах тега testCase.

Окно настроек TestCase
Окно настроек TestCase
Соответствие атрибутов в XML и настроек в GUI

Атрибут тега testCase

Настройка в GUI

failOnError

Basic/Abort on Error

failTestCaseOnErrors

Basic/Fail TestCase on error

keepSession

Basic/Session

maxResults

Basic/Max Result

searchProperties

Basic/Search Properties

discardOkResults

Basic/Discard OK Result

timeout

Basic/TestCase timeout

wsrmEnabled

WS-RM/WS-RM Enabled

wsrmVersion

WS-RM/WS-RM Version

wsrmAckTo

WS-RM/WS-RM Ack To

wsrmExpires

WS-RM/WS-RM Expires

amfAuthorisation

AMF/AMF Session

amfEndpoint

AMF/endpoint

amfLogin

AMF/login

amfPassword

AMF/password

Если вы запускаете проекты через командную строку, то следите, чтобы названия Test Suite не повторялись, так как они будут перезаписывать результаты выполнения друг друга. Также SoapUI автоматически заменяет пробелы на нижние подчеркивания и удаляет такие знаки, как «‑», «=» и другие.

testStep

Всего SoapUI «из коробки» предоставляет 14 видов testStep. Они представлены на скриншоте:

Виды Test Steps
Виды Test Steps

В меню Add Step встречаются Drop MQTT Connection, Publish using MQTT, Receive MQTT Message — они по умолчанию не поддерживаются. Если попытаться их создать без дополнительной настройки окружения, то в XML‑файле успешно сохранится новый testStep, но проект в GUI открываться перестанет.

Каждый testStep имеет 4 атрибута: type, name, disabled, id и дочерние теги settings, config, может встречаться description. В зависимости от вида элемента меняется наполнение тега config. Например, для Groovy Script указывается атрибут type=groovy и он имеет один дочерний config/script.

Пример Groovy-скрипта с запуском
Пример Groovy-скрипта с запуском
Для сравнения, SOAP Request имеет более сложную структуру
<con:testStep type="request" name="SOAP Request" id="7d1a1663-6ddc-401b-9327-a172dc37d990">
    <con:settings/>
    <con:config xsi:type="con:RequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <con:interface>BirdManagementPortBinding</con:interface>
        <con:operation>getBird</con:operation>
        <con:request name="SOAP Request" id="8d5cc343-b5f5-4bbe-8e40-5770e6c3ddbf" outgoingWss=""
                     incomingWss="" useWsAddressing="true" useWsReliableMessaging="true">
            <con:encoding>UTF-8</con:encoding>
            <con:endpoint>${#Project#MOCK_BirdManagement}</con:endpoint>
            <con:request><![CDATA[<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:bird="http://www.bercut.com/cc/sa/schema/birdmanagement" xmlns:com="http://www.bercut.com/schema/commonInVoiceAPI">\r
<soapenv:Header/>\r
<soapenv:Body>\r
<bird:getBird>\r
<bird:birdSpecies>беркут</bird:birdSpecies>\r
<!--1 or more repetitions:-->\r
<!--Optional:-->\r
<acc:lifeTime>?</acc:lifeTime>\r
</acc:getBird>\r
</soapenv:Body>\r
</soapenv:Envelope>]]></con:request>
            <con:assertion type="SOAP Response" id="563120f0-a5a7-40cf-b3c6-06c8e211fbe9"/>
            <con:assertion type="Schema Compliance" id="21bc2d30-31a4-4560-ba40-b96ab6944a78">
                <con:configuration/>
            </con:assertion>
            <con:assertion type="SOAP Fault Assertion" id="d0fa610b-ae31-4852-9a19-921a00f9ec64"/>
            <con:assertion type="XPath Match" id="15f8825c-1f1f-4430-816e-0f62ca27287e" name="XPath Match">
                <con:configuration>
                    <path>//*[local-name()='birdSpecies'][1]/*[local-name()='birdSpeciesId']</path>
                    <content>1</content>
                    <allowWildcards>false</allowWildcards>
                    <ignoreNamspaceDifferences>false</ignoreNamspaceDifferences>
                    <ignoreComments>false</ignoreComments>
                </con:configuration>
            </con:assertion>
            <con:credentials>
                <con:username>admin</con:username>
                <con:password>admin</con:password>
                <con:domain>adminadmin</con:domain>
                <con:selectedAuthProfile>Basic</con:selectedAuthProfile>
                <con:addedBasicAuthenticationTypes>Basic</con:addedBasicAuthenticationTypes>
                <con:authType>Global HTTP Settings</con:authType>
            </con:credentials>
            <con:attachment>
                <con:name>текст_выступления.docx</con:name>
                <con:contentType>application/octet-stream</con:contentType>
                <con:contentId>текст_выступления.docx</con:contentId>
                <con:url>C:/bird_go_to_party/текст_выступления.docx</con:url>
                <con:id>a4f18f0b-0092-463c-90cf-cd4c285ccce7</con:id>
            </con:attachment>
            <con:jmsConfig JMSDeliveryMode="PERSISTENT"/>
            <con:jmsPropertyConfig/>
            <con:wsaConfig mustUnderstand="TRUE" version="200508" addDefaultAction="true"/>
            <con:wsrmConfig version="1.2"/>
        </con:request>
    </con:config>
</con:testStep>

Обратите внимание, что пароли из Creditails обычно хранятся в открытом виде, даже если в GUI они скрыты за точками.

Пример отображения паролей в GUI
Пример отображения паролей в GUI
Пример сохраненных паролей в XML
Пример сохраненных паролей в XML

loadTest

LoadTest предназначен для нагрузочного тестирования существующих Test Steps.

Таблица соответствия GUI и XML

GUI

XML

Комментарии

Threads

threadCount

LoadTest Options/Sample Interval

sampleInterval

LoadTest Options/Thread Setup Delay

startDelay

LoadTest Options/"Calculate TPS/BPS"

calculateTPSOnTimePassed

true/false

LoadTest Options/Reset Statistics

resetStatisticsOnThreadCountChange

LoadTest Options/Disable History

historyLimit

0 соответствует отмеченной галочке, другие значения - не отмеченной, по умолчанию = -1

Limit (первое окошко с числами)

testLimit

Limit (второе окошко с типом лимита)

limitType

Например, COUNT_PER_THREAD

Strategy

loadStrategy/type

Например, Simple

Test Delay

loadStrategy/config/testDelay

Random

loadStrategy/config/randomFactor

В GUI отображается без точки, в XML с точкой, например, 43.0

LoadTest Options/Max Assertions in Log

maxAssertionErrors

LoadTest Options/вкладка Statistics Log/Log Folder

statisticsLogFolder

LoadTest Options/вкладка Statistics Log/Log Interval

statisticsLogInterval

по умолчанию, 0

LoadTest Options/вкладка Statistics Log/Log on ThreadCount change

logStatisticsOnThreadChange

true/false 

LoadTest Options/Cancel Running

cancelOnReachedLimit

LoadTest Options/Cancel Excessive

cancelExcessiveThreads

true/false

Strategy Interval

strategyInterval

LoadTest Options/TestStep Statistics

updateStatisticsPerTestStep

true/false 

В теге часто используются дочерние settings, например, для управления настройками HTTP:

<con:settings>
  <con:setting id="HttpSettings@include_request_in_time_taken">false</con:setting>
  <con:setting id="HttpSettings@include_response_in_time_taken">false</con:setting>
  <con:setting id="HttpSettings@close-connections">true</con:setting>
</con:settings>

И вот такая настройка для loadTest типа request:

<con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting>

В GUI эти настройки можно найти в разделе Options у testStep (например, ctrl+shift+O или правая кнопка мыши на нужном testStep → Options, или правая кнопка мыши на нужном testStep → Show Editor → шестерёнка).

Assertion в LoadStep представляют собой теги assertion с атрибутами type (в GUI он выбирается при добавлении нового assertion) и name. Также разные типы таких проверок могут содержать дополнительные структуры, например:

<con:assertion type="Step Status" name="Step Status"/>
<con:assertion type="Step Maximum" name="Step Maximum">
  <con:configuration>
    <name>Step Max Maximum</name>
    <min-requests>100</min-requests>
    <max-value>1000</max-value>
    <test-step>start mock</test-step>
    <max-errors>70</max-errors>
  </con:configuration>
</con:assertion>
Отображение в GUI
Отображение в GUI

securityTest

Позволяет применять различные сценарии тестирования на безопасность к существующим testStep.

В разделе SecurityTest Options представлены всего 2 настройки: Abroad on Error и Fail SecurityTest on Error. Они связаны с атрибутами failOnError и failSecurityTestOnScanErrors. Также присутствует атрибут name.

Окно настроек SecurityTest
Окно настроек SecurityTest

В дочернем теге settings описываются настройки логирования (Log Options):

<con:settings>
  <con:setting id="com.eviware.soapui.security.log.JSecurityTestRunLog$OptionsForm@max_rows">
    154
  </con:setting>
  <con:setting id="com.eviware.soapui.security.log.JSecurityTestRunLog$OptionsForm@errors_only">
    false
  </con:setting>
</con:settings>
Окно настроек логирования
Окно настроек логирования

В редакторе теста на безопасность перечислены все testStep из testCase, в котором расположен SecurityTest. При этом недоступные для тестирования объекты обозначены светло‑серым цветом.

Отображения списка доступных для тестирования на безопасность TestSteps
Отображения списка доступных для тестирования на безопасность TestSteps

Больше всего вариантов готовых сценариев у SOAP Request, затем идет REST Request, HTTP Request, в самом конце — GraphQL Request без подготовленных сценариев, только пользовательские (Custom).

securityTest включает в себя набор testStepSecurityTest по одному для каждого тестируемого testStep.

Пример наполнения testStepSecurityTest
<con:testStepSecurityTest>
    <con:testStepId>7d1a1663-6ddc-401b-9327-a172dc37d990</con:testStepId>
    <con:testStepSecurityScan type="FuzzingScan" name="Fuzzing Scan" id="c679ee72-ac05-4495-b22e-1392079095da" applyForFailedStep="false" disabled="false" runOnlyOnce="true">
        <con:settings/>
        <con:config xsi:type="con:FuzzerScan" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <con:minimal>5</con:minimal>
            <con:maximal>15</con:maximal>
            <con:numberOfRequest>100</con:numberOfRequest>
        </con:config>
        <con:testStep/>
        <con:checkedParameters/>
        <con:executionStrategy xsi:nil="true" immutable="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <con:strategy>ALL_AT_ONCE</con:strategy>
            <con:delay>100</con:delay>
        </con:executionStrategy>
    </con:testStepSecurityScan>
</con:testStepSecurityTest>

Первым дочерним тегом для testStepSecurityTest будет testStepId со значением атрибута ID из связанного тега testStep. После идентификатора идет перечень testStepSecurityScan. Если вы планируете исправлять SoapUI‑проект или генерировать его с нуля, обратите внимание на согласованность этих ID.

XML-атрибуты testStepSecurityTest и GUI

XML

GUI

Комментарии

type

Выбирается при добавлении нового SecurityScan

Тип применяемого сценария сканирования, например, SQLInjectionScan

name

Отображаемое имя

через GUI его изменить нельзя

applсyForFailedStep

Apply to Failed TestSteps на вкладке Strategy

runOnlyOnce

Run only once на вкладке Strategy

Оставшиеся настройки из этой вкладки в XML записываются в дочерний для testStepSecurityScan тег executionStrategy, у которого в свою очередь есть тег strategy - Select strategy (значением может быть ONE_BY_ONE или ALL_AT_ONCE), delay - Request Delay (ms).

Первый дочерний тег settings пустой, затем идет config с перечислением настроек, которые требуются выбранному сценарию. У него в атрибутах также указывается type, но в этот раз добавляется неймспейс:

<con:config xsi:type="con:FuzzerScan" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <con:minimal>5</con:minimal>
  <con:maximal>15</con:maximal>
  <con:numberOfRequest>100</con:numberOfRequest>
</con:config>

Для каждого сценария используется свой набор параметров, в GUI они расположены на вкладке Advanced в редакторе Security Scan. Для некоторых Security Scan их может не быть в принципе, но в XML все равно должен быть тег config. Например, для Boundary Scan:

<con:config xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>

Встречающийся в SoapUI‑проекте атрибут xsi:nil и его неймспейс xmlns:xsi=http://www.w3.org/2001/XMLSchema‑instance для заполнения не обязательны и их можно проигнорировать.

Дочерний по отношению к testStepSecurityTest тег testStep появляется при создании Security Scan, не связан с элементами в GUI (по крайней мере, мне эту связь установить не удалось). SoapUI корректно открывает проект, если этого тега нет.

Пример Security Scan
Пример Security Scan

Следующий дочерний тег — checkedParameters. Он соответствует разделу Parameters в настройках SecurityScan, если они предусмотрены для выбранного типа.

Соответствие XML и GUI

атрибут в XML

отображение в GUI

label

Label

parameterName

Name

xpath

XPath

checked

Enabled

Например, для скриншота выше XML будет выглядеть следующим образом:

<con:checkedParameters>
  <con:parameters label="tets" parameterName="Username" xpath="" checked="true"/>
</con:checkedParameters>

В редакторе Security Scan на вкладке Assertions каждая строка является тегом assertion в XML. В его атрибутах указывается type, например, «Invalid HTTP Status Codes». name по умолчанию совпадает с типом, в GUI assertion можно переименовать через кнопку F2. Индивидуальные настройки каждого типа assertion перечисляются в дочерних тегах codes:

<con:assertion type="Invalid HTTP Status Codes" id="f6ead976-b5f0-44e6-a69c-f6701f2207a5"
name="Invalid HTTP Status Codes For Kittens">
  <con:configuration>
    <codes>505</codes>
  </con:configuration>
</con:assertion>

mockService

Чтобы MockService гарантированно подтянул изменения, нужно:

  1. Если mock запущен, то остановить его.

  2. Сохранить проект.

  3. Запустить mock снова.

MockService отвечает за эмуляцию работы сторонних сервисов, в XML он обозначается как тег mockService. Бывает двух видов: restMockService (для WADL‑интерфейсов) и mockService (для WSDL‑интерфейсов), основное отличие — это тип операций: restMockAction для REST и mockOperation для SOAP. Можно добавлять несколько интерфейсов.

Соответствие параметров mockService в XML и GUI

XML атрибут

отображение в GUI

Комментарии

path

Path

port

Port

требует прямого указания порта, то есть в XML-файле нельзя указать "${#Project#MOCK_PORT}" - нужно "8080"

host

Host

можно настраивать через переменные или напрямую

bindToHostOnly

Host Only

docroot

Docroot 

faultMockOperation

Fault Operation

При создании нового mock атрибут faultMockOperation будет отсутствовать и появится только после того, как вы заполните соответствующее поле

name

наименование MockService

dispatchResponseMessages

MockService Properties "Dispatch Responses"

в XML появляется, только когда параметр изменяется в GUI
по умолчанию, false

<con:mockService  port="8089" path="/" host="${#Project#MOCK_IP}" name="MockService_bird" bindToHostOnly="false" docroot="" faultMockOperation="extinctBird" dispatchResponseMessages="true">

Настройки «Match SOAP Version», «Require SOAP Action» и количество строк логов хранятся в теге settings.

Настройки логирования MockService
Настройки логирования MockService
<con:settings>
  <con:setting id="com.eviware.soapui.impl.wsdl.mock.WsdlMockService@require-soap-action">true</con:setting>
  <con:setting id="com.eviware.soapui.impl.wsdl.mock.WsdlMockService@require-soap-version">true</con:setting>
  <con:setting id="com.eviware.soapui.impl.wsdl.panels.mock.WsdlMockServiceDesktopPanel$LogListModel@maxSize">50</con:setting>
</con:settings>

mockService имеет тег properties для хранения своих Custom Properties и тег description, который можно задать через GUI в MockService Properties → Description или в MockService Editor → description.

Окно в GUI для редактирования описания MockService
Окно в GUI для редактирования описания MockService

Скриптам из вкладок «Start Script», «Stop Script», «OnRequest Script», «AfterRequest Script» соответствуют теги startScript, stopScript, onRequestScript, afterRequestScript. «OnRequest Script» и «AfterRequest Script» применяются, когда на mock приходит запрос. Бывает полезно добавить в «OnRequest Script» логирование запроса:

log.info(this.mockRequest.getHttpRequest());
log.info(this.mockRequest.getRequestHeaders());
log.info(this.mockRequest.getRequestContent());

В зависимости от количества интерфейсов и операций, которые использованы в MockService, время запуска mock может увеличиваться. Например, вы видите в логах, что ваш mock успешно запустился, но при попытке к нему обратиться, возвращается ошибка: Cannot invoke "javax.wsdl.BindingOperation.getExtensibilityElements()" because "bindingOperation" is null.

Ошибка из-за неуспевшего запуститься мока
Ошибка из-за неуспевшего запуститься мока

В наших проектах обычно хватало паузы в 6 секунд, а для особенно больших mock — 12 или 24 секунд.

mockOperation

mockOperation — основной тег, ради которого и создают mockService. В нем содержатся ответы на запросы для SOAP‑операций, которые могут принадлежать разным WSDL‑интерфейсам. Для создания тега необходимо указать атрибуты: наименование — name, соответствующий интерфейс — interface, название мокирующейся операции operation.

Способ, по которому будет определяться возвращаемый ответ, указывается в теге dispatchStyle. Для способов XPATH и SCRIPT дополнительно появляется тег dispatchPath.

Дочерними тегами будут:

  1. settings

  2. defaultResponse

  3. dispatchStyle — способ, по которому будет определяться возвращаемый ответ

  4. dispatchPath — заполняется значением из окна под зеленой стрелочкой, если dispatchStyle XPATH или SCRIPT

  5. dispatchConfig — заполняется, если dispatchStyle = QUERY_MATCH

Самый важный дочерний тег — defaultResponse. Он должен быть обязательно заполнен названием существующего mockResponse, иначе будет возникать ошибка com.eviware.soapui.impl.wsdl.mock.DispatchException: Failed to find MockResponse. Она может появиться как из‑за неправильной генерации проекта внешними утилитами, так и при работе самого SoapUI.

Дочерние теги для defaultResponse:

  1. name — название условия выбора

  2. query — выражение XPath

  3. match — значение, которому должен соответствовать результат выполнения query (Expected Value)

  4. response — название mockResponse, который нужно вернуть (Dispatch to)

  5. disabled

Окно с настройками роутинга mockResponse
Окно с настройками роутинга mockResponse

Скриншот выше соответствует следующему коду:

<con:dispatchConfig xsi:type="con:MockOperationQueryMatchDispatch"
                    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <con:query>
        <con:name>11</con:name>
        <con:query>123</con:query>
        <con:match>true</con:match>
        <con:response>Response 6</con:response>
        <con:disabled>true</con:disabled>
    </con:query>
    <con:query>
        <con:name>success</con:name>
        <con:query>//*[local-name()='code'] = 'create_new_buy'</con:query>
        <con:match>true</con:match>
        <con:response>Response 6</con:response>
        <con:disabled>true</con:disabled>
    </con:query>
</con:dispatchConfig>

Дочерний тег response состоит из имени (name), httpResponseStatus (по умолчанию 200, может возвращать 500), encoding (по умолчанию «UTF-8»). Среди дочерних тегов к response есть settings, script, responseContent непосредственно с текстом запроса, например, SOAP‑запрос будет обернут в <![CDATA[...]]>, в GUI же будет отображаться только сам запрос.

Окно генерации ответа с ошибкой
Окно генерации ответа с ошибкой

Также дочерним к response будет тег wsaConfig:

<con:wsaConfig mustUnderstand="NONE" version="200508" action="http://www.bercut.com/BirdLifeCycle/endBirdLifeResponse"/>

Здесь важно отметить атрибут action, в зависимости от загруженного wsdl он может быть и полным путем до элемента‑ответа операции, а может иметь только ее название. Больше разных настроек можно найти на вкладке WS‑A.

Атрибут version в GUI представлен как выпадающий список из двух значений: 200 508 и 200 408. Если же обойти ограничения интерфейса и прописать другой номер версии в SOAP‑проекте, то ваш mockResponse перестанет открываться, как минимум на редактирование. В логах можно будет найти ошибку:

com.jgoodies.binding.beans.PropertyAccessException: Failed to read an adapted Java Bean property.cause=org.apache.xmlbeans.impl.values.XmlValueOutOfRangeException: string value '2005008' is not a valid enumeration value for WsaVersionType in namespace http://eviware.com/soapui/config

В графическом интерфейсе флаг «Enable WS‑A addressing» указывает на то, используются ли настройки из этой секции (WS‑A).

Иногда атрибуты тега wsaConfig удаляются из файла XML.

Кроме тела ответа, можно также добавлять скрипты:

import javax.xml.xpath.*
import groovy.xml.StreamingMarkupBuilder
import groovy.lang.Binding;
import groovy.lang.Script;
 
def util = new com.eviware.soapui.support.GroovyUtils( context )
def xml = new XmlSlurper().parseText(mockRequest.requestContent)
def v_transact_id = xml.Header.TransactionIdentifier
// create XmlHolder for request content
def holder = new com.eviware.soapui.support.XmlHolder( mockRequest.requestContent )
 
// get target testcase
def mock_service = mockResponse.mockOperation.mockService.project
def testCase = mock_service.testSuites["TransactionProcess"].testCases['Rollback']
testCase.setPropertyValue("transact_id", v_transact_id.toString())
def runner = testCase.run( new com.eviware.soapui.support.types.StringToObjectMap(), false )
Отображение скриптов в GUI
Отображение скриптов в GUI

В примере сначала из запроса к mock получают параметр TransactionIdentifier. Затем через переменную mockResponse осуществляется доступ к объекту SoapUI‑проекта, перемещаются на уровень testSuite и находят определённый testCase, в котором сформирован SOAP‑запрос. После этого заполняются переменные и запускается testCase. В результате, перед отправкой ответа, mock отправляет дополнительный запрос к внешней системе. Такой подход можно использовать, если системы требуют параллельных действий помимо основного запроса‑ответа.

restMockAction

По структуре restMockAction похож на mockOperation, но имеет меньший набор вариантов для выбора ответа: dispatchStyle может быть или SEQUENCE, или SCRIPT и другие атрибуты: name (по умолчанию, совпадает с resourcePath), method — название http метода, resourcePath — часть url, по которому располагается операция, например, «/accountcreation», id.

В атрибутах дочернего тега response появляется mediaType с информацией о структуре возвращаемых данных. В GUI для его определения предлагается раскрывающийся список, но при этом нет защиты от неправильных значений. Если поменять в XML‑файле его значение на набор неизвестных символов, то SoapUI корректно откроет проект.

Неправильное значение поля Content | Media type
Неправильное значение поля Content | Media type

В остальном атрибуты совпадают с mockOperation. В дочерних тегах отсутствует информация для WSA, но есть тег header для заполнения HEADER в HTTP.

SoapUI и Groovy 

Во многих элементах поддерживаются скрипты на Groovy, начиная с testCase и выше по дереву элементов. Он помогает создавать более сложные проверки, автоматически запускать элементы проекта и т. д. Скрипты чаще всего называются Setup Script или TearDown Script, само слово «Script» указывает на возможность использовать Groovy.

В верхнем правом углу редактора указаны переменные, которые доступны из скрипта. В исходном коде можно найти больше информации про них, а также их связь с другими более крупными объектами.

Пример окна для скрипта в GUI
Пример окна для скрипта в GUI

В официальной документации или вот тут можно найти полезные примеры скриптов.

Если вносите правки в XML‑файл тестов, особенно, когда применяете форматирование, следите, чтобы структура Groovy‑кода не поменялась, так как SoapUI применяет скрипты как написано в XML‑файле со всеми пробелами, отступами и т. д.

Пример скрипта, который получает SOAP‑ответ из testStep, парсит его по тегу variable. Далее для каждого тега он собирает дополнительную информацию и вызывает с ними testCase. Такой сценарий можно использовать, когда настройки хранятся на отдельном сервисе, в процессе тестирования они меняются и хочется быть уверенным, что после прогона стенд вернется к изначальному состоянию.

import javax.xml.xpath.*
import groovy.xml.StreamingMarkupBuilder
import groovy.lang.Binding;
import groovy.lang.Script;
 
def util = new com.eviware.soapui.support.GroovyUtils( context )
def testCase =  testRunner.testCase
def testStepSetValue = testCase.getTestStepByName("setValue")
 
def  resp = testCase.testSuite.testCases['Start_mock'].getTestStepByName("getGroupWithType").getProperty("Response")
 
def  xmlResp = util.getXmlHolder(resp.value.toString())
 
for(v=1;v<Integer.parseInt(xmlResp["count(//variable)"]);v++){
  def opName = xmlResp["//variables/variable[$v]/name"];
  def opType = xmlResp["//variables/variable[$v]/type"];
  def opValue = testCase.testSuite.getProperty(opName).value;
   
  testCase.setPropertyValue("currOpParamName", opName );
  testCase.setPropertyValue("currOpParamType", opType );
  testCase.setPropertyValue("currOpParamValue", opValue);
  testStepSetValue.run(testRunner, context);
}

В SoapUI много мест, где можно использовать Groovy. Наша практика показала, что удобнее использовать дополнительные testSuite/testCase/testSteps вместо скриптов: логирование проще и понятнее, ошибки записываются в отчет о тестировании. А главное, такие проекты удобнее поддерживать — не нужно просматривать каждый объект, в попытке найти то самое место, которое ведет себя неправильно. Элементы test* видны сразу и, если они имеют хорошее название, то считываются быстрее. Также с ними удобнее управлять прогоном, включая и выключая необходимые.

Заключение

Работа над статьей действительно оказалась «приключением на 20 минут»: на её написание у меня ушло более года. В основе материала лежит опыт, который я приобрела в процессе рефакторинга и автоматизации проектов SoapUI. Изначально обе части представляли собой единый текст, но объем оказался слишком большим, и, в конечном итоге, было удобнее разделить их на две статьи. Несмотря на масштабность работы, мне не удалось охватить все аспекты, которые хотелось бы отразить.

Я старалась добавить как можно больше перекрестных ссылок для удобства навигации, чтобы читателям было проще ориентироваться в тексте. Вторую часть сложнее воспринимать как единый текст, но она окажется полезной, если обращаться к конкретным разделам.

Что касается автоматизации юнит‑тестирования: теперь при каждом мерж‑реквесте автоматически поднимается стенд в Docker, запускаются тесты, а их результаты отправляются в корпоративный мессенджер. Кроме того, мы разработали инструмент для генерации шаблонов новых SoapUI‑проектов. Задача выполнена.

Комментарии (0)