Симуляция web service-ов с помощью soapUI
Одна из основных проблем, которые возникают во время интеграции различных систем между собой это то, что на момент разработки эти сервисы либо не существуют, либо не всегда доступны (или доступны с большими проблемами). Такое может случиться, если, к примеру, компания разрабатывает приложение на базе SOA, и каждый из сервисов создается параллельно разными людьми. Ждать пока один человек закончит свой компонент, прежде чем приступать к своей разработке – не самый эффективный способ. Хорошо, если все сервисы находятся в руках одной компании, тогда можно еще хоть как то договориться, но в реальности все бывает как раз наоборот – сервисы находятся под контролем сторонних компаний и бывает очень сложно повлиять на их разработку. Чтобы это было легче понять – представим гипотетическую ситуацию.
Существует некая компания, которая занимается выполнение различного рода технических работ, например ремонтирует/контролирует/устанавливает охранные системы. У компании есть регистр данных клиентов, хранящийся в какой-то базе данных. Доступ к этой базе данных можно получить через специальный пользовательский интерфейс, через который данные о клиентах заносятся в систему, просматриваются и обновляются. Когда приходит новый заказ, то он оформляется в еще одной специальной системе заказов, после чего на объект отправляется техник, который собственно и занимается обслуживанием охранных систем. У техника есть общая инструкция, описывающая, как он должен действовать на объекте, но, в принципе, каждый из них действует по собственному усмотрению, исходя из ситуации на месте. После выполнения работы – техник создает отчет в свободной форме, который сохраняется в некой третьей системе.
Предположим, что компания хочет улучшить качество отчетов. Она хочет видеть, какие именно работы были сделаны, сколько времени занимала каждая из них, какие проблемы наиболее частые и так далее. Всю эту информацию планируется использовать для улучшения производительности и, как результат, снижения расходов и увеличения оборота. Для этого планируется внедрить новую информационную систему, которая позволит стандартизировать рабочий процесс. Выглядит это как список задач/checklist на PDA техника, которые он должен выполнить, посетив объект. Эта же система позволит паковать заказы таким образом, чтобы одному технику доставались заказы в одной и той же части города, тем самым увеличив количество объектов, которые он может посетить за день. Нанимать работника в штат компания не желает и поэтому нанимается контрактор, который, собственно, и интегрирует эти системы между собой. Вот тут начинается самое интересaное.
Как правило, базы данных, хранящие клиентов, заказы, отчеты, доступны внутри корпоративной сети, но не видны снаружи по причинам безопасности. В то же время, даже находясь внутри сети, доступ можно получить только напрямую подсоединившись к базе данных. В принципе, контрактор может организовать доступ к этим базам через специальные соединения, но это в таком случае, он будет очень сильно зависеть от доступности и работоспособности этих систем. Второе особенно важно, так как доступ, скорее всего можно получить не к live системам, а к тестировочным, которые, как правило, имеют обыкновение работать нестабильно. К тому же, любое новое звено в доступе к данным увеличивают стоимость разработки, так как в случае проблем приходится просматривать все звенья.
Прямой доступ к базе данных не является наилучшим решением. Конечно, это можно сделать, но лучше представить несколько базы данных как отдельный сервис. Это обеспечит меньшую зависимость от баз данных и позволит в будущем без проблем заменить существующие системы на одну общую, тем самым, предположим, сократив издержки на обслуживание и, возможно, лицензии. К сожалению, у компании такого сервиса пока нет, но она пообещала контрактору, что если он предоставит им интерфейс, который должен реализовывать этот сервис, то они создадут его. Но! В течении месяца. Ouch. Контрактор не может позволить себе ждать месяц. Обычное решение этой проблемы – создать симуляторы сервисов, которые будут эмулировать внешние системы согласно контракту. Вот о том, как сделать это наиболее эффективно и пойдет здесь речь.
Симулятор всегда можно написать вручную, будь то обычный perl скрипт, который слушает на определенном порту и посылающий обратно данные или это java web service сервер, эмулирующий ту же задачу. К сожалению, все эти решения довольно ресурсоемкие. Другой подход – использование готовых инструментов, для создания довольно динамичных заглушек. Один из таких инструментов – soapUI.

Для создания симулятора веб сервиса, нам потребуется soapUI версии 2.5, WSDL файл, описывающий интерфейс, 30 минут времени и чашка кофе для настроения.
SoapUI это инструмент, который позволяет тестировать web сервисы, вызывать методы на интерфейсах, анализировать ответы и создавать пакеты тестов наподобие xUnit. А начиная с версии 1.7, soapUI позволяет симулировать web сервисы.
Для начала – скачаем soapUI 2.5 с сайта www.soapui.org. Оттуда же можно запустит soapUI через WebStart если на машине установлена Java 1.5 JDK.
Следующий шаг, для того, чтобы создать симулятор – в запущенном soapUI, создайте новый проект, где укажите путь к вашему WSDL файлу. Здесь, в примере, я буду использовать существующий WSDL файл, который позволяет получить курс валют. WSDL интерфейс для этого сервиса расположен здесь: http://www.webservicex.net/CurrencyConvertor.asmx?wsdl. Чтобы создать новый проект, нажмите File->New soapUI project.

Начиная с версии 2.5 можно сразу создать так называемый mockService, поэтому поставьте галочку „Create a Web Service Simulation of the imported WSDL“. Впрочем, если это не было выбрано с самого начала, то можно создать новый MockService используя контекстное меню будь то проекта, операции интерфейса или самого запроса. Если “Create MockService” выбран, то появится еще одно диалоговое окно, предлагающее настроить MockService.

В этом диалоговом окне можно указать какие операции следует симулировать, где и по какому порту будет расположен симулятор. Например, если указать Path = /mockCurrencyConvertorSoap, а Port = 8088, то симулятор будет доступен по адресу http://127.0.0.1:8088/mockCurrencyConvertorSoap, а WSDL документ по адресу http://127.0.0.1:8088/mockCurrencyConvertorSoap?WSDL. «Add Endpoint» означает, что адрес симулятора будет доступен во время тестирования из soapUI, а поставив галочку на «Start MockService» можно сразу же запустить MockService. После нажатия OK появится еще одно окно, где нужно будет ввести название симулятора MockService.

В результате, должно появиться что-то похожее на следующее:

Отличить симулятор от теста можно тем, что иконки симулятора выглядят серыми. По умолчанию так же откроется редактор MockService, из которого можно запустить/настроить симулятор, настроить логи, а так же добавить различные скрипты, которые будут выполняться при определенных событиях. Нажав на зеленую кнопку можно запустить симулятор.

Готово! Теперь этот сервис доступен по адресу http://127.0.0.1:8088/mockCurrencyConvertorSoap. Этот адрес можно получить, нажав на зеленую кнопку I, которая откроет WSDL сервиса в браузере.
То, какие ответы будет посылать симулятор, зависит от того, что указано в MockResponse и как настроен MockOperation. Начнем сначала с MockResponse. Выберите Response 1 в проекте и откройте редактор.

Это тот XML файл, который будет отправляться каждый раз, когда кто-то вызовет метод симулятора. Кстати, скорее всего вид окна будет отличаться от моего – поиграйте с опциями в правом верхнем углу, пока не получите тот вариант, который больше всего вас устраивает. Чтобы протестировать симулятор – вызовите соответствующий метод в своем коде или выберите Request 1 в soapUI. Затем измените endpoint в редакторе, как указано ниже:

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

Этот редактор содержит два сообщения – верхнее это последний отправленный запрос на конвертацию валют, нижнее – ответ, MockResponse, который должен отправить симулятор. Для добавления динамичности, MockResponse использует ${variableName}, чтобы ссылаться на переменные, сгенерированные во время запроса. Эти переменные содержатся в context-е, который инициализируется в Script блоке. В данном случае, rate будет колебаться от 1 до 2 случайным образом. Это легко проверить, запустим проверочный Request 1 запрос:

Если таких запросов было много, то MockService редактор позволит просмотреть их, используя Message Log блок.

Иногда, необходимо более сложное поведение симулятора. Например, для пары EUR->USD нужно генерировать ставку одним способом, для USD->JPY другим, а для всех остальных пар нужно вообще посылать SOAP Fault. Это можно достичь, используя специальный механизм координации (dispatching).

Для начала создадим необходимый MockResponse для USD->JPY. Ставка колеблется случайным образом от 100 до 150.

Чтобы создать Fault response – в меню MockResponse выбрать соответствующую иконку и отредактировать так, как это требует контракт.

Например, faultcode может быть 404, а faultstring утверждать, что было невозможно определить ставку.
Настроить координацию можно в MockOperation редакторе, выбрав правильный Dispatch метод. Sequence означает, что MockResponse будут посылаться один за другим: на каждый запрос по одному ответу. Random – ответы посылаются в случайном порядке.

Нас же интересует либо Xpath, либо Script. XPath позволяет более просто создавать условия, какое сообщение должно быть отправлено на запрос.

Declare namespace web=’http://www.webserviceX.NET/’;
concat(//web:FromCurrency/text(), “->”, //web:ToCurrency/text(), “ Response”)
Когда Xpath выбран, то становится доступен Dispatch(XPATH) блок. Он описывает, какое сообщение должно быть использовано в качестве ответа. Для этого, последняя строка должна содержать имя MockResponse-а. Если имя не найдено, то ответ будет тот, который указан в Default Response. В данном случае, это Fault Response.

def groovyUtils = new com.eviware.soapui.support.GroovyUtils (context)
def holder = groovyUtils.getXmlHolder ( mockRequest.requestContent )
def fromCurrency = holder.getNodeValue("//web:FromCurrency/text()")
def toCurrency = holder.getNodeValue("//web:ToCurrency/text()")
return fromCurrency + "->" + toCurrency + " Response"
Тоже самое, но немного более гибко, можно сделать, используя Groovy скрипт. Здесь та же логика, как и в случае с Xpath, просто Groovy позволяет использовать более гибкие конструкции, нежели Xpath. Впрочем, в большинстве случаев это лишь дело вкуса.
Возможности SoapUI не ограничиваются одними SOAP сообщениями. Можно динамически настраивать не только само SOAP сообщения, но и редактировать HTTP Header-ы, отправлять Attachmentы и, даже, использовать WS-Addressing. К сожалению, бесплатная версия SoapUI ограничивается лишь синхронными запросами, тогда как асинхронные ответы можно создавать только в платной версии soapUI. Тем не менее, SoapUI является отличным инструментом для симулирования веб сервисов на стадии разработки.
- Войдите на сайт для отправки комментариев