Удаленка для jenkins+selenide+selenoid+allure+docker спецов на 2-3 часа в день. 100% remote! Присоединиться к проекту

Автоматизация асинхронных веб-сервисов?


(Mykhailo Poliarush) #1

Если тестировать синхронные веб-сервисы с помощью SoapUI, то он отлично работает, а вот если у вас асинхронные, то тут не так уже просто и интуитивно понятно что делать.
Поиск на форуме http://www.soapui.org/ внятных ответов и четких действий не дает.
Кто сталкивался с таким тестированием? Если да, то как последовательность шагов нужно сделать?

Задача: посылаем запрос на веб-сервис 1, получаем синхронный ответ, а потом через 10 минут получаем асинхронный ответ на веб-сервис2 и веб-сервис3

Буду благодарен за любую помощь.


(Дмитрий Жарий) #2

 

Я мало чем могу помочь, но все таки хотел бы уточнить
Тут все ясно:
1. посылаем запрос на веб-сервис 1, получаем синхронный ответ
А тут нет, если веб-сервис2 и сервис3 что то получили в ответ, то значит они что-то запрашивали? У кого они запрашивали, у веб-сервиса1? Или это сам веб-сервис 1 сделал запрос на веб-сервисы 2 и 3?
2. а потом через 10 минут получаем асинхронный ответ на веб-сервис2 и веб-сервис3

Я мало чем могу помочь, но все таки хотел бы уточнить

 

Тут все ясно:

1. посылаем запрос на веб-сервис 1, получаем синхронный ответ

 

А тут нет, если веб-сервис2 и сервис3 что то получили в ответ, то значит они что-то запрашивали? У кого они запрашивали, у веб-сервиса1? Или это сам веб-сервис 1 сделал запрос на веб-сервисы 2 и 3?

2. а потом через 10 минут получаем асинхронный ответ на веб-сервис2 и веб-сервис3

 

И какой транспорт? HTTP? TCP/IP?


(Mykhailo Poliarush) #3

система огромная, не указал всех деталей. 

но ты сделал такую картинку, что даже вопрос  не надо перефразировать.

да ситуация ровно, как на картинке и используется HTTP протокол

з.ы. сам рисовал? :)


(Дмитрий Жарий) #4

Тогда скорее всего нужно отдельно протестировать синхронные запросы

От имени клиента:

Клиент делает запрос на веб-сервис1 и получает ответ.

 

От имени веб-сервиса1

Вебсервис1 делает синхронный запрос на веб-сервис2 с уже подготовленными данными и получает ответ.

И т.д.

 

Или

возможно,  после того, как вебсервис1 сделает запрос на веб-сервис2 и веб-сервис3, то в данных вебсервисе1 могут произойти некоторые изменения в данных, которые может получить клиент.

В таком случае, клиент в цикле с таймаутом в 10 минут запрашивает эти измененные данные у веб-сервиса1.

 

 На счет картинки – да, рисовал сам, но при помощи отличного инструмента RealDraw, на который я даже денег не пожалел



(Mykhailo Poliarush) #5

не все так просто, тут просто участвуют не только веб сервисы, а другие системы, которые выполняют какую-то логику и как только системы заканчивают обработку данных, высылают результат в ввиде асинхронного ответов на веб-сервис.

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


(Дмитрий Жарий) #6

Тут вот в чем дело,
Главное не перепутать кто и когда выступает в роли клиента, а кто в виде сервиса.
Вот, предположим, следующая ситуация:
Есть два веб сервиса:
Веб-сервис1 и веб-сервис2

Сначала веб-сервис1 спрашивает веб-сервис2:
Дай мне информацию о погоде в Киеве за последние 10 лет и пришли ее с идентификатором 12345.
Int requestId = 12345;
WebService2.GetHistory(12345, “Kyiv, 10 years”).
И в этом случае WebService2 отвечает что окей, я ее сейчас соберу, через 10 минут будет.
В этом случае веб-сервис1 выступает в роли клиента, а веб-сервис2 в роли сервера. Но, запрос был синхронным. Ответ был получен сразу же. И веб-сервис1 начал заниматься своими делами, а веб-сервис2 начал процессить данные.

Через некоторое время, веб-сервис2 закончил задачу и готов отослать данные веб-сервису1.
Веб-сервис2 знает, что ID задачи было 12345 и шлет данные веб-сервису1:
Int requestId = 12345;
WebService1.UpdateHistory(12345, “Weather data for request Kyiv, 10 years in this string”).
И в данном случае веб-сервис1 стал сервером, а веб-сервис2 оказался клиентом.

Но, в данном случае, два запроса были синхронными. Потому что ответ и на первый и на второй запрос был получен сразу же. А вот сама операция, состоящая из двух запросов была асинхронной.

В таком случае, чтобы получить второй запрос от веб-сервиса2, soapUI должен сам стать веб-сервисом. Может быть эту задачу можно решить с помощью Моков?


(Mykhailo Poliarush) #7

да все верно, но вот только если перейти к практике, то не сильно получается. вот есть такая красивая картинка, кейс которой я хочу проверить

Description of Figure 4-3 follows

да нужно использовать моки, но вот успеха пока что не вижу.

проколупался уже 2 часа - нетривиально одним словом!


(Дмитрий Жарий) #8

Задача никуда не ушла, но зато теперь она хорошо проиллюстрирована :)

 

Может ли SoapIU запустить внешнею программу?

Если это сложно сделать но soapUI, то я бы реализовал тест тест на Java/.NET в отдельном exe-шнике, запустил бы  как внешнее приложение через soapUI и получил бы результат теста через консольный вывод.

Это, конечно же – костыль, но иногда тулза не оставляет другого выбора.


(Mykhailo Poliarush) #9

просто soapUI уже использует заказчик только не в полную силу,
мне всегда казалось, что там все очень просто делается, 
а вот асинхронные сервисы не пошли :(

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


(Alexandra) #10

Привет! Другого варианта, как использовать моки - не вижу :(

1. Стартуешь мок сервис (типа Callback Service, моку задаёшь респонс Confirmation, кот. он должен возвращать).

2. Отправляешь реквест на Asynshronous WebService.

3. Сразу получаешь Confirmation response.

4. Delay 10 min

5. Проверяешь, что пришло на CallbackMock, и что мок ответил.

 

Единственный нюанс - нужно знать, как настроить систему, чтобы Asynshronous WebService возвращал второй респонс на мок, а не на реальный сервис.


(Alexandra) #11

Если нужна какая-то информация по работе с моками, пиши, буду рада помочь :)


(Mykhailo Poliarush) #12

спасибо Саша, а ты не могла бы выслать пример кода, т.е. сделать один два теста простых c моком, заархивировать проект и положить сюда линку?


(Alexandra) #13

Да, я написала такой простенький пример

Суть такая:

1. По втянутому в проект интерфейсу WSDLа создаём мок (правой кнопкой на интерфейсе, Generate MockService). В поле Path указываем URL, который хотим использовать для мока. Например, вводим /CurrencyConvertorMock, также указываем порт, на котором будет мок крутиться, например 8088. Таким образом, мы ожидаем, что наш веб-сервис будет посылать реквест на адрес http://localhost:8088/CurrencyConvertorMock (вместо локалхост  может быть айпишник твоей машины - в общем, зависит от того, как нужно будет настраивать URL, куда будет отправляться второй реквест). После того, как мок создан, желательно открыть его Options  и в поле host прописать localhost. (иначе, там будет имя твоей машины, и тест будет работать только с твоей машины)

Мок создан - ура

2. Редактируем Response мока (что мы хотим, чтобы мок отвечал, в твоём случае - пример Confirmation 2)

3. Далее можно написать OnRequest Script - код, который будет выполняться, как только на мок что-то пришло. Пример кода:

def project = mockRunner.getMockService().getProject()
project.properties['r_mockResult'].value = mockRequest.requestContent
log.info 'MockRequest: ' + mockRequest.requestContent

//Example how to save parameter which came to mock
def holder = new com.eviware.soapui.support.XmlHolder( mockRequest.requestContent )
project.properties['r_fromCurrency'].value =  holder["//*:FromCurrency"]

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

Вообще, на моке можно много всякого кода писать. Можно с помощью груви скрипта прописывать динамические респонсы (например, у тебя респонс зависит от того, что пришло в реквесте). Также можно что-то интересное прописать в AfterRequestScript. Например, можно прописать, что после реквеста, мок сам отправляет какой-то реквест куда-то. Пример кода:

def request = project.getInterfaceByName("AnotherInterfaceInProject").getOperationByName("PublishRequest").getRequestByName("Request 1")
 request.submit( new com.eviware.soapui.impl.wsdl.WsdlSubmitContext( request ), false )

 

4. Мок создан и все необходимые скрипты на нём написаны. Переходим в степам непосредственно тест кейса.

Сначала стартуем мок, с помощью Groovy скрипта:

def project = context.testCase.getTestSuite().getProject();
def mockService = project.getMockServiceByName("CurrencyConvertorMock");
mockService.start();

5. Ставим небольшой Delay, чтоб мок нормально успел стартовать

6. Паблишим реквест на наш асинхронный веб-сервис

(у меня в тесте я паблишу реквест прямо на мок сразу, но это сути не меняет - ты можешь запаблишить на какой-то другой сервис, а он уже будет прописан так, чтобы посылать потом реквест на твой мок).

7. Delay - мок работает, ждём

8. Стопаем мок:

def project = context.testCase.getTestSuite().getProject();
def mockService = project.getMockServiceByName("CurrencyConvertorMock");
def mockRunner = mockService.getMockRunner();
mockRunner.stop();

9. Далее я  предлагаю сделать groovy script степ, в котором провалидировать данные, кот. пришли на мок:

//Get request which came to mock
def r_mockResult = context.expand( '${#Project#r_mockResult}' )
//now you may perform any assertions with it

//Example of assertion
def r_fromCurrency = context.expand( '${#Project#r_fromCurrency}' )
assert r_fromCurrency == 'USD', 'Currency is incorrect'

 


(Alexandra) #14

Если есть wsdl в открытом доступе какого-то асинхронного веб-сервиса - давай, я могу на его примере сделать то же самое. У меня просто не было времени поискать, поэтому сделала на обычном