SOAP и веб-сервисы XML на платформе.Net. Web-сервис SOAP в Eclipse
Алексей Бойко
SOAP и веб-сервисы XML на платформе.Net
Веб-сервисы XML предлагают такой уровень совместимости и взаимодействия в отношении операционных систем,
платформ и языков, который ранее был просто недоступен.
Эндрю Троелсен (обладатель титула MVP (Most Valuable Professional in Microsoft))
Если вы еще не работали с веб-сервисами XML, то наверняка слышали слово «SOAP». Настало время разобраться с этими понятиями.
Intro
Если вас интересует Интернет или сети поменьше, скорее всего рано или поздно вы столкнетесь с веб-сервисами XML. Веб-сервис XML – это не только веб-приложение, способное выводить информацию в браузер. Скорее это технология удаленного взаимодействия, позволяющая вызывать методы и свойства объекта в сети с помощью стандартных HTTP-запросов.
На практике это означает, что клиенты такого сервиса могут быть написаны на различных языках и для разных операционных систем.
В качестве информационного «транспорта» между сервисом и клиентом можно использовать HTTP-методы GET или POST.
А можно «наложить» поверх еще один протокол – SOAP (Simple Object Access Protocol). Обычно так и поступают, так как в этом случае возможна передача сложных типов (включая пользовательские). А классические методы GET и POST поддерживают только перечни, простые массивы и строки.
Пример SOAP-взаимодействия
SOAP-сообщение – это XML-документ, помещенный в тело HTTP-запроса.
Листинг 1. Структура SOAP-сообщения
Взаимодействие клиента и сервиса происходит следующим образом:
- клиент формирует SOAP-запрос и отправляет его сервису;
- сервис на удаленном компьютере выполняет процедуру и отправляет SOAP-ответ.
Например, вот так может выглядеть SOAP-запрос, вызывающий метод HelloWorld() удаленного веб-сервиса XML:
Листинг 2. Пример SOAP-запроса
Метод HelloWorld(), как и полагается, возвращает строку «Здравствуй, мир!»:
Листинг 3. Пример SOAP-ответа
Xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
Создание веб-сервиса XML на платформе.NET 2.0
Создать сервис можно различными способами, мы будем использовать Visual Studio 2005. Нажмите «File -> New -> Web Site», в раскрывшемся окне выберите «ASP.NET web Service». По указанному при создании адресу вы обнаружите следующие файлы и директории (см. рис. 1).
В принципе, сервис может содержать только один-единственный файл с расширением *.asmx. (Для обозначения веб-сервисов.Net используется расширение *.asmx.) В данном случае это не так, посмотрите содержимое файла Service.asmx:
Листинг 4. В Service.asmx определен внешний файл поддержки
<%@ WebService Language="C#" CodeBehind="~/App_Code/Service.cs" class="Service" %>
Атрибут CodeBehind указывает внешний файл, расположенный в папке App_Code, в котором размещен программный код, реализующий метод HelloWorld():
Листинг 5. Файл Service.cs, реализующий метод HelloWorld()
using System;
using System.Web;
using System.Web.Services;
Public Service () {
Return "Hello World";
Возможно создать единственный файл Service.asmx без кода поддержки, обладающий теми же функциональными возможностями:
Листинг 6. Service.asmx без внешнего кода поддержки
<%@ WebService Language="C#" class="Service" %>
using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
public class Service: System.Web.Services.WebService
Public Service () {
Public string HelloWorld() {
Return "Hello World";
Нам это ни к чему, и так поступать мы не станем.
Как видите, единственный метод нашего веб-сервиса помечен атрибутом , информирующим среду выполнения ASP.NET о том, что этот метод доступен для поступающих HTTP-запросов. Не обозначенные таким атрибутом члены не будут доступны клиентским программам.
Для наших экспериментов вполне подходит такой простой сервис, осталось только опубликовать его.
Публикация веб-сервиса XML с помощью IIS
Речь пойдет не о публикации в Интернете, а о создании условий для тестирования нашего сервиса на локальном компьютере.
Первым делом установите IIS (Internet Information Server). Для этого откройте окно «Установка и удаление программ» и выберите в нем «Установка компонентов Windows». (Некоторые версии Windows не предполагают установку IIS, например Windows XP Home Edition.)
Примечание: сервер IIS лучше устанавливать раньше, чем.Net Framework, иначе придется настроить IIS на поддержку.Net-приложений с помощью запуска утилиты командной строки aspnet_regiis.exe (с флагом /i).
Создайте виртуальный каталог. Если вы используете Windows XP Pro, войдите в «Панель управления -> Администрирование -> Internet Information Services». В раскрывшемся окне выберите «Действие -> Создать -> Виртуальный каталог».
Будет запущен мастер создания виртуальных каталогов. Укажите в качестве псевдонима Soap1 и задайте путь к каталогу, в котором хотите разместить сервис, например C:\Soap1. Теперь скопируйте туда содержимое нашего веб-сервиса.
Наберите в адресной строке браузера http://localhost/soap1/Service.asmx, и вы должны увидеть страницу тестирования сервиса (см. рис. 2).
Просмотр SOAP-сообщений
Страница тестирования не позволяет отправлять и читать SOAP-сообщения. По этой причине придется воспользоваться сторонними разработками, я рекомендую использовать soapUI. (Это бесплатный продукт, доступный по адресу http://www.soapui.org .)
После установки soapUI создайте новый проект под наз-ванием soap1, оставив поле Initial WSDL пустым (см. рис. 3).
Правой кнопкой мышки щелкните на только что созданном проекте и выберите «Add WSDL from URL». В открывшемся диалоговом окне введите http://localhost/soap1/Service.asmx?wsdl. Теперь у нас есть возможность отправлять SOAP-запросы к нашему сервису и просматривать полученные ответы. (Запросы будут сгенерированы soapUI автоматически.)
Что же такое этот WSDL? Документ WSDL описывает возможности взаимодействия клиентов с веб-сервисом. Там описывается, какие методы сервиса доступны для внешнего вызова, какие параметры они принимают и что возвращают, а также прочая информация, необходимая для удаленного взаимодействия. Такой документ можно составить вручную, а можно доверить его генерацию серверу, для этого достаточно приписать суффикс?wsdl к URL, указывающему на файл *.asmx.
Чтобы посмотреть WSDL-документ нашего сервиса, введите в браузере http://localhost/soap1/Service.asmx?wsdl. Информацию именно из этого документа использует soapUI для автоматической генерации SOAP-запросов.
SOAP Extensions
Как вы, наверное, заметили для создания веб-сервиса XML (как и клиента) не обязательно заботиться о виде SOAP-сообщений. Достаточно пометить нужные методы атрибутом , и среда выполнения ASP.NET сама составит пакеты нужного формата.
На рис. 4 показаны запрос и ответ веб-сервиса, полученные с помощью программы soapUI.
Повторим еще раз. Запрос сгенерирован soapUI – при создании реальных клиентов для сервиса тоже не требуется вручную форматировать SOAP-пакеты. В создании ответа сервиса мы также не принимали непосредственного участия. Все это происходит автоматически.
Однако вполне вероятно, что вам потребуется самостоятельно модифицировать эти пакеты. Например, произвести сжатие или шифрование передаваемых данных. В этом и есть назначение SOAP Extensions.
SOAP Extensions – это механизм, позволяющий произвольным образом изменять принимаемые и отправляемые SOAP-сообщения.
«Путь» SOAP-сообщения
Чтобы приступить к программированию, нужно рассмотреть путь, который проходит SOAP-сообщение, прежде чем оно будет получено и обработано соответствующим методом (см. рис. 5).
SOAP-сообщение можно рассматривать как XML-документ, описывающий передаваемый по сети объект. Перед тем как использовать переданный таким образом объект, его нужно восстановить (или, если хотите, собрать) из этого описания. Этой цели служит XML-сериализатор.
Входящие пакеты проходят десериализацию (восстановление объекта из XML-описания), а отправляемые сериализацию (создание XML-описания объекта).
На рис. 5 показаны четыре точки (BeforeSerialize, AfterDeserialize, BeforeDeserialize, AfterSerialize), в которых мы, с помощью SOAP Extensions, можем перехватить SOAP-сообщение. Модифицировать его и отправить дальше.
Реализация SOAP Extension
Для начала определимся с заданием: пусть мы хотим изменить отправляемые веб-сервисом SOAP-пакеты как показано в листинге 7:
Листинг 7. «Старый» и новый ответы web-сервиса XML
Xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
Xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
Зашифрованный текст
План действий для реализации SOAP Extension:
- Создаем dll с классом, наследуемым от SoapExtension.
- Добавляем к нашему веб-сервису папку bin и кладем туда созданную dll.
- Добавляем к сервису файл web.config и вносим в него нужные изменения.
Роль папки bin и файла web.config рассмотрим позже.
Создание DLL c SOAP Extension
Создайте новый проект «Class Library» под названием SoapExtensionLib. В этом проекте потребуется реализовать только один класс, который будет выполнять необходимые нам модификации SOAP-пакетов. Этот класс должен быть наследованным от класса SoapExtension.
Листинг 8. Создание класса, наследуемого от SoapExtension
using System;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.IO;
using System.Net;
using System.Xml;
Каждое SOAP Extension получает как параметр поток, содержащий передаваемый по сети объект (до или после сериализации). И обязано возвращать поток.
SOAP Extension можно представить как «врезку», которую можно поставить в одной или всех четырех точках (BeforeSerialize, AfterDeserialize, BeforeDeserialize, AfterSerialize), показанных на рис. 5. В каждой точке таких «врезок» может быть сколько угодно (см. рис. 6).
Для получения этих потоков используется метод ChainStream.
Листинг 9. Реализация метода ChainStream
public class TraceExtension: SoapExtension
Stream wireStream;
Stream appStream;
// метод в качестве входного параметра
// получает поток, содержащий передаваемый объект
Public override Stream ChainStream(Stream stream)
WireStream = stream;
AppStream = new MemoryStream();
Return appStream;
…
В точке BeforeDeserialize поток wireStream содержит принятый из сети SOAP-запрос. Этот SOAP-запрос нужно передать потоку приложения (потоку appStream).
А в точке AfterSerialize необходимо передать потоку wireStream отправляемый в сеть SOAP-ответ, который будет размещаться в appStream.
Для работы с потоками в каждой из четырех точек нужно реализовать метод ProcessMessage.
Листинг 10. Реализация метода ProcessMessage, не модифицирующего SOAP-сообщения
// ProcessMessage, выполняющий обязательное копирование
// потоков в двух точках (BeforeDeserialize и AfterSerialize)
Switch (message.Stage)
// в точке BeforeDeserialize необходимо передать
// SOAP-запрос из потока сети (wireStream)
// в поток приложения (appStream)
Case SoapMessageStage.BeforeDeserialize:
Copy(wireStream, appStream);
AppStream.Position = 0;
Break;
// в точке AfterSerialize необходимо передать
// SOAP-ответ из потока приложения в поток сети
AppStream.Position = 0;
Break;
void Copy(Stream from, Stream to)
TextReader reader = new StreamReader(from);
TextWriter writer = new StreamWriter(to);
Writer.WriteLine(reader.ReadToEnd());
Writer.Flush();
Листинг 10 можно воспринимать как болванку для дальнейших экспериментов. В такой реализации метода ProcessMessage нет никакого смысла – исходящий SOAP-ответ никак не модифицируется. Исправим это:
Листинг 11. Реализация метода ProcessMessage, модифицирующего SOAP-ответ
public override void ProcessMessage(SoapMessage message)
Switch (message.Stage)
Case SoapMessageStage.AfterSerialize:
WriteOutput(message);
Break;
// часть кода вырезана для экономии места
// перепишем SOAP-ответ
public void WriteOutput(SoapMessage message)
AppStream.Position = 0;
// создадим XML документ из потока
XmlDocument document = new XmlDocument();
Document.Load(appStream);
// Для использования XPath нужно определить
// NamespaceManager
XmlNamespaceManager nsmgr = new XmlNamespaceManager(document.NameTable);
Nsmgr.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");
XmlNode ResultNode = document.SelectSingleNode("//soap:Body", nsmgr);
// заменем содержимое узла
ResultNode.InnerText = "зашифрованный текст";
// очистим поток и запишем в него новый SOAP-ответ
AppStream.SetLength(0);
AppStream.Position = 0;
Document.Save(appStream);
// ОБЯЗАТЕЛЬНОЕ ДЕЙСТВИЕ
// передадим SOAP-ответ из потока приложения (appStream)
// в поток сети (wireStream)
AppStream.Position = 0;
Copy(appStream, wireStream);
Далее нужно определить два метода (один из которых является перегруженным, т.е. может вызываться с разными наборами параметров), которые в нашем случае не нужны. Однако мы обязаны определить их в соответствии с правилами наследования от класса SoapExtension.
Листинг 12. Другие обязательно реализуемые методы
// В соотвествии с правилами наследования мы обязаны
// определить эти методы, однако мы их никак не используем
public override object ?
GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute)
Return null;
public override object GetInitializer(Type WebServiceType)
Return null;
public override void Initialize(object initializer)
Return;
Всё, компилируем проект. Наконец-то мы получили dll с SOAP Extension. Полный листинг SoapExtensionLib.dll находится на сайте журнала в разделе «Исходный код».
Настройка веб-сервиса для работы с SOAP Extension
Опять откройте проект нашего веб-сервиса XML с помощью Visual Studio. Нажмите «WebSite -> Add Reference» и выберите созданный ранее SoapExtensionLib.dll.
К проекту автоматически будет добавлена папка Bin. На файлы *.dll, расположенные в папке Bin, приложение ссылается автоматически.
Теперь положите в директорию веб-сервиса файл Web.Config следующего содержания:
Листинг 13. Файл Web.Config
Priority="1"
Group="0" />
Теперь структура нашего сервиса выглядит так, как показано на рис. 7. С помощью файла Web.Config мы информируем среду ASP.NET о том, что мы добавили к веб-сервису XML Soap Extension, реализованное в классе TraceExtension который расположен в файле SoapExtensionLi.dll. Листинг 14. Секция webServices в файле Web.Config
Priority="1"
Group="0" />
Как вы уже знаете, можно сделать множество SOAP Extension, и поток, несущий в себе передаваемый объект (до или после сериализации), будет проходить через каждое из них. Порядок прохождения потоком различных SOAP Extension задается с помощью атрибутов priority и group. Стоит отметить, что сконфигурировав данным способом Web.Config, мы информируем среду о том, что наше SOAP Extension будет вызываться для каждого метода сервиса, помеченного атрибутом . Существует возможность создать свой атрибут и помечать им только те методы, для которых нужно вызвать SOAP Extension. Листинг 15. Пример использования собственного атрибута
public string HelloWorld() {
Return "Hello World";
Для этого требуется добавить в SoapExtensionLi.dll класс, наследованный от SoapExtensionAttribute (см. рис. 8). Заключение
В данной статье отражены основные моменты построения и функционирования веб-сервисов XML на платформе.Net. Я надеюсь, что изложенного материала будет вполне достаточно, чтобы при необходимости вы смогли заняться более глубоким изучением темы. Вконтакте hats
23 июля 2013 в 13:09
Всем привет! Я надеюсь, что после прочтения топика вы сможете самостоятельно: И все же, я что-то забыл! Если еще немного порефлексировать, то стоит отметить, что клиент за раз может отправить на сервер как одно sms-сообщение, так и некоторое их количество. Другими словами, в одном пакете данных может быть от одного до бесконечности сообщений. В результате мы получаем, что для отправки sms-сообщения нам необходимы следующие данные: На первый вопрос мы ответили, теперь необходимо ответить на второй вопрос. И пожалуй, я позволю себе немного с халтурить. Поэтому, с сервера мы будем присылать только булевы данные, значение которых имеет следующий смысл: На этом мы закончили описание постановки задачи! И наконец-то приступим к самому интересному – будем разбираться что за диковинный зверь этот SOAP! И начну я свое повествование с того, что данный протокол обмена данными относится к подмножеству протоколов основанных на так называемой парадигме RPC (Remote Procedure Call, удалённый вызов процедур) антиподом которой является REST (Representational State Transfer, передача репрезентативного состояния). Более подробно об этом можно прочесть в Wikipedia, ссылки на статьи находятся в самом конце топика. Из этих статей нам надо уяснить следующее: «Подход RPC позволяет использовать небольшое количество сетевых ресурсов с большим количеством методов и сложным протоколом. При подходе REST количество методов и сложность протокола строго ограничены, из-за чего количество отдельных ресурсов может быть большим». Т.е., применительно к нам это означает, что на сайте в случае RPC подхода будет всегда один вход (ссылка) на сервис и какую процедуру вызывать для обработки поступающих данных мы передаем вместе с данными, в то время как при REST подходе на нашем сайте есть много входов (ссылок), каждая из которых принимает и обрабатывает только определенные данные. Если кто-то из читающих знает, как еще проще объяснить различие в данных подходах, то обязательно пишите в комментариях! Следующее, что нам надо узнать про SOAP – данный протокол в качестве транспорта использует тот самый XML, что с одной стороны очень хорошо, т.к. сразу же в наш арсенал попадает вся мощь стека технологий основанных на данном языке разметки, а именно XML-Schema – язык описания структуры XML-документа (спасибо Wikipedia!), который позволяет производит автоматическую валидацию поступающих на сервер данных от клиентов. И так, теперь мы знаем, что SOAP – протокол используемый для реализации удаленного вызова процедур и в качестве транспорта он использует XML! Если почитать статью на Wikipedia, то оттуда можно узнать еще и о том, что он может использоваться поверх любого протокола прикладного уровня, а не только в паре с HTTP (к сожалению, в данном топике мы будем рассматривать только SOAP поверх HTTP). И знаете, что мне во всем этом больше всего нравится? Если нет никаких догадок, то я дам подсказку – SOAP!… Всеравно не появилось догадок?… Вы точно прочли статью на Wikipedia?… В общем, не буду вас дальше мучить. Поэтому, сразу перейду к ответу: «SOAP (от англ. Simple Object Access Protocol - простой протокол
доступа к объектам; вплоть до спецификации 1.2
)». Самое примечательное в этой строчке выделено курсивом! Я не знаю какие выводы сделали вы из всего этого, но мне видится следующее – поскольку данный протокол ну никак нельзя назвать «простым» (и видимо с этим согласны даже в w3), то с версии 1.2 он вообще перестал как-то расшифровываться! И стал называться SOAP, просто SOAP и точка. Ну да ладно, прошу меня извинить, занесло немного в сторону. Как я писал ранее, в качестве транспорта используется XML, а пакеты, которые курсируют между клиентом и сервером называются SOAP-конвертами. Если рассматривать обобщенную структуру конверта, то он вам покажется очень знакомым, т.к. напоминает структуру HTML-страницы. В нем есть основной раздел – Envelop
, который включает разделы Header
и Body
, либо Fault
. В Body
передаются данные и он является обязательным разделом конверта, в то время как Header
является опциональным. В Header
может передаваться авторизация, либо какие-либо иные данные, которые на прямую не относятся к входным данным процедур веб-сервиса. Про Fault
особо рассказывать нечего, кроме того, что он приходит в клиент с сервера в случае возникновения каких-либо ошибок. На этом мой обзорный рассказ про протокол SOAP заканчивается (более детально сами конверты и их структуру мы рассмотрим когда наши клиент и сервер наконец-то научатся запускать их друг в друга) и начинается новый – про компаньона SOAP под названием WSDL
(Web Services Description Language). Да-да, это та самая штука, которая отпугивает большинство из нас от самой попытки взять и реализовать свое API на данном протоколе. В результате чего, мы обычно изобретаем свой велосипед с JSON в качестве транспорта. И так, что такое WSDL? WSDL – язык описания веб-сервисов и доступа к ним, основанный на языке XML (с) Wikipedia. Если из этого определения вам не становится понятным весь сакральный смысл данной технологии, то я попытаюсь описать его своими словами! WSDL предназначен для того, чтобы наши клиенты могли нормально общаться с сервером. Для этого в файле с расширением «*.wsdl» описывается следующая информация: Основная задачи схемы – описать структуру данных которые мы собираемся обрабатывать. Все данные в XML-схемах делятся на простые
(скалярные) и коплексные
(структуры) типы. К простым типам относятся такие типы как: Предлагаю далеко не ходить и написать XML-схему для нашего sms-сообщения! Ниже представлено xml-описание sms-сообщения: Думаю, что значение элементов «element
» и «complexType
» вам стало все более-менее понятно, поэтому не будем на них больше заострять внимание и переключимся сразу же на элемент-композитор «sequence
». Когда мы используем элемент-композитор «sequence
» мы сообщаем о том, что элементы включенные в него должны всегда располагаться в указанной в схеме последовательности, а также все из них являются обязательными. Но не стоит отчаиваться! В XML-схемах есть еще два элемента-композитора: «choice
» и «all
». Композитор «choice
» сообщает о том, что должен быть какой-то один из перечисленных в нем элементов, а композитор «all
» – любая комбинация перечисленных элементов. Как вы помните, то в первом разделе топика мы договорились о том, что в пакете может передаваться от одного до бесконечности sms-сообщений. Поэтому предлагаю разобраться как такие данные декларируются в XML-схеме. Общая структура пакета может выглядеть следующим образом: Второй блок схемы декларирует элемент «messageList
» типа «MessageList
». Видно, что «MessageList
» представляет собой комплексный тип, который включает минимум один элемент «message
», но максимальное число таких элементов не ограничено! Вообще, для того, чтобы у нас все работало правильно нам надо передавать клиенту WSDL-файл с правильным MIME-типом. Для этого необходимо настроить ваш веб-сервер соответствующим образом, а именно – установить для файлов с расширением «*.wsdl» MIME-тип равный следующей строке: Application/wsdl+xml
Header("Content-Type: text/xml; charset=utf-8");
Хочу сразу предупредить, наш простенький веб-сервис будет иметь довольно внушительное описание, поэтому не пугайтесь, т.к. большая часть текста является обязательной водой и написав ее один раз можно постоянно копировать от одного веб-сервиса к другому! Поскольку WSDL – это XML, то в самой первой строке необходимо прямо об этом и написать. Корневой элемент файла всегда должен называться «definitions
»:
После этого мы объявляем о том, что в нашем веб-сервисе «SmsService
» есть точка входа («port»), которая называется «SmsServicePort
». Именно в эту точку входа и будут отправляться все запросы от клиентов к серверу. И указываем в элементе «address
» ссылку на файл-обработчик, который будет принимать запросы. После того, как мы определили веб-сервис и указали для него точку входа – необходимо привязать к нему поддерживаемые процедуры:
После этого нам необходимо привязать процедуру к сообщениям:
Теперь нам необходимо описать сами сообщения, т.е. входящие и исходящие:
Теперь надо сделать самую малость – добавить описание данных типов в наш WSDL-файл! И как вы думаете, как описываются в WSDL входящие и исходящие данные? Думаю, что вы уже все давно поняли и сказали сами себе, что при помощи XML-схем! И вы будете абсолютно правы!
После того, как все было установлено и настроено нам необходимо будет создать в корневой папке вашего хостинга файл «smsservice.php
» со следующим содержанием: setClass("SoapSmsGateWay");
//Запускаем сервер
$server->handle();
Теперь мы подошли к серверу! Как видим, весь SOAP-сервер занимает всего лишь три строки! В первой строке мы создаем новый экземпляр объекта SoapServer и передаем ему в конструктор адрес нашего WSDL-описания веб-сервиса. Теперь мы знаем, что он будет располагаться в корне хостинга в файле с говорящим именем «smsservice.wsdl.php
». Во второй строке мы сообщаем SOAP-серверу какой класс необходимо дергать для того, чтобы обработать поступивший с клиента конверт и вернуть конверт с ответом. Как вы могли догадаться, именно в этом классе будет описан наш единственный метод sendSms
. В третьей строке мы запускаем сервер! Все, наш сервер готов! С чем я нас всех и поздравляю! Теперь нам необходимо создать WSDL-файл. Для этого можно либо просто скопировать его содержимое из предыдущего раздела, либо позволить себе вольности и немного его «шаблонизировать»: ";
?>
messageList = new MessageList();
$req->messageList->message = new Message();
$req->messageList->message->phone = "79871234567";
$req->messageList->message->text = "Тестовое сообщение 1";
$req->messageList->message->date = "2013-07-21T15:00:00.26";
$req->messageList->message->type = 15;
$client = new SoapClient("http://{$_SERVER["HTTP_HOST"]}/smsservice.wsdl.php",
array("soap_version" => SOAP_1_2));
var_dump($client->sendSms($req));
После того, как мы определили объекты, нам необходимо создать объект ($req
), который будем отправлять на сервер. После чего идут две самые заветные для нас строки! Наш SOAP-клиент! Верите или нет, но этого достаточно для того, чтобы на наш сервер начали сыпаться сообщения от клиента, а также для того, чтобы наш сервер успешно их принимал и обрабатывал! В первой из них мы создаем экземпляр класса SoapClient и передаем в его конструктор адрес расположения WSDL-файла, а в параметрах явно указываем, что работать мы будем по протоколу SOAP версии 1.2. В следующей строке мы вызываем метод sendSms
объекта $client
и сразу же выводим в браузере результат. Мне с сервера вернулся следующий объект: Object(stdClass)
public "status" => boolean true
Теперь посмотрим на лог, который мы предусмотрительно ведем на серверной стороне! В первой его части мы видим необработанные данные, которые поступили на сервер:
Object(stdClass)
public "messageList" =>
object(stdClass)
public "message" =>
object(stdClass)
public "phone" => string "79871234567" (length=11)
public "text" => string "Тестовое сообщение 1" (length=37)
public "date" => string "2013-07-21T15:00:00.26" (length=22)
public "type" => string "15" (length=2)
// создаем объект для отправки на сервер
$req = new Request();
$req->messageList = new MessageList();
$msg1 = new Message();
$msg1->phone = "79871234567";
$msg1->text = "Тестовое сообщение 1";
$msg1->date = "2013-07-21T15:00:00.26";
$msg1->type = 15;
$msg2 = new Message();
$msg2->phone = "79871234567";
$msg2->text = "Тестовое сообщение 2";
$msg2->date = "2014-08-22T16:01:10";
$msg2->type = 16;
$msg3 = new Message();
$msg3->phone = "79871234567";
$msg3->text = "Тестовое сообщение 3";
$msg3->date = "2014-08-22T16:01:10";
$msg3->type = 17;
$req->messageList->message = $msg1;
$req->messageList->message = $msg2;
$req->messageList->message = $msg3;
Object(stdClass)
public "messageList" =>
object(stdClass)
public "message" =>
object(stdClass)
public "Struct" =>
array (size=3)
0 =>
object(stdClass)
public "phone" => string "79871234567" (length=11)
public "text" => string "Тестовое сообщение 1" (length=37)
public "date" => string "2013-07-21T15:00:00.26" (length=22)
public "type" => string "15" (length=2)
1 =>
object(stdClass)
public "phone" => string "79871234567" (length=11)
public "text" => string "Тестовое сообщение 2" (length=37)
public "date" => string "2014-08-22T16:01:10" (length=19)
public "type" => string "16" (length=2)
2 =>
object(stdClass)
public "phone" => string "79871234567" (length=11)
public "text" => string "Тестовое сообщение 3" (length=37)
public "date" => string "2014-08-22T16:01:10" (length=19)
public "type" => string "17" (length=2)
$req->messageList->message = (object)$req->messageList->message;
Object(stdClass)
public "messageList" =>
object(stdClass)
public "message" =>
object(stdClass)
public "BOGUS" =>
array (size=3)
0 =>
object(stdClass)
public "phone" => string "79871234567" (length=11)
public "text" => string "Тестовое сообщение 1" (length=37)
public "date" => string "2013-07-21T15:00:00.26" (length=22)
public "type" => string "15" (length=2)
1 =>
object(stdClass)
public "phone" => string "79871234567" (length=11)
public "text" => string "Тестовое сообщение 2" (length=37)
public "date" => string "2014-08-22T16:01:10" (length=19)
public "type" => string "16" (length=2)
2 =>
object(stdClass)
public "phone" => string "79871234567" (length=11)
public "text" => string "Тестовое сообщение 3" (length=37)
public "date" => string "2014-08-22T16:01:10" (length=19)
public "type" => string "17" (length=2)
// создаем объект для отправки на сервер
$req = new Request();
$msg1 = new Message();
$msg1->phone = "79871234567";
$msg1->text = "Тестовое сообщение 1";
$msg1->date = "2013-07-21T15:00:00.26";
$msg1->type = 15;
$msg2 = new Message();
$msg2->phone = "79871234567";
$msg2->text = "Тестовое сообщение 2";
$msg2->date = "2014-08-22T16:01:10";
$msg2->type = 16;
$msg3 = new Message();
$msg3->phone = "79871234567";
$msg3->text = "Тестовое сообщение 3";
$msg3->date = "2014-08-22T16:01:10";
$msg3->type = 17;
$req->messageList = $msg1;
$req->messageList = $msg2;
$req->messageList = $msg3;
$req->messageList = (object)$req->messageList;
Object(stdClass)
public "messageList" =>
object(stdClass)
public "BOGUS" =>
array (size=3)
0 =>
object(stdClass)
public "phone" => string "79871234567" (length=11)
public "text" => string "Тестовое сообщение 1" (length=37)
public "date" => string "2013-07-21T15:00:00.26" (length=22)
public "type" => string "15" (length=2)
1 =>
object(stdClass)
public "phone" => string "79871234567" (length=11)
public "text" => string "Тестовое сообщение 2" (length=37)
public "date" => string "2014-08-22T16:01:10" (length=19)
public "type" => string "16" (length=2)
2 =>
object(stdClass)
public "phone" => string "79871234567" (length=11)
public "text" => string "Тестовое сообщение 3" (length=37)
public "date" => string "2014-08-22T16:01:10" (length=19)
public "type" => string "17" (length=2)
Лирическая часть.
Представьте что у вас реализована или реализуется некая система, которая должна быть доступна извне. Т.е. есть некий сервер, с которым вам надо общаться. Например веб-сервер. Этот сервер может выполнять множество действий, работать с базой, выполнять какие-то сторонние запросы к другим серверам, заниматься каким-то вычислениями и т.д. жить и возможно развиваться по ему известному сценарию (т.е. по сценарию разработчиков). С таким сервером общаться человеку неинтересно, потому что он может не уметь/не хотеть отдавать красивые странички с картинками и прочим юзер-френдли контентом. Он написан и работает чтобы работать и выдавать на запросы к нему данные, не заботясь, чтоб они были человекочитаемые, клиент сам с ними разберется. Другие системы, обращаясь к этому серверу уже могут распоряжаться полученными от этого сервера данными по своему усмотрению - обрабатывать, накапливать, выдавать своим клиентам и т.д. Ну вот, один из вариантов общения с такими серверами - это SOAP. SOAP протокол обмена xml-сообщениями. Практическая часть.
Веб-сервис (так называется то, что предоставляет сервер и то, что используют клиенты) дает возможность общения с сервером четко структурированными сообщениями. Дело в том, что веб-сервис не принимает абы какие данные. На любое сообщение, которое не соответствует правилам, веб-сервис ответит ошибкой. Ошибка будет, кстати, тоже в виде xml с четкой структурой (чего нельзя сказать правда о тексте сообщения). WSDL (Web Services Description Language). Правила, по которым составляются сообщения для веб-сервиса описываются так же с помощью xml и также имеют четкую структуру. Т.е. если веб-сервис предоставляет возможность вызова какого-то метода, он должен дать возможность клиентам узнать какие параметры для данного метода используются. Если веб-сервис ждет строку для метода Method1 в качестве параметра и строка должна иметь имя Param1, то в описании веб-сервиса эти правила будут указаны. В качестве параметров могут передаваться не только простые типы, но и объекты, коллекции объектов. Описание объекта сводится к описанию каждой составляющей объекта. Если объект состоит из нескольких полей, значит описывается каждое поле какой у него тип, название (какие возможные значения). Поля также могут быть сложного типа и так далее пока описание типов не закончится на простых - строка, булево, число, дата... Впрочем простыми могут оказаться какие-то специфические типы, важно чтоб клиенты могли понять какие значения могут в них содержаться. Для клиентов достаточно знать url веб-сервиса, wsdl всегда будет рядом, по которому можно получить представление о методах и их параметрах, которые предоставляет этот веб-сервис. Какие плюсы у всех этих наворотов:
Описание, имеющее четкую структуру, читается любым soap-клиентом. Т.е. какой бы ни был веб-сервис, клиент поймет какие данные веб-сервис принимает. По этому описанию клиент может построить свою внутреннюю структуру классов объектов, т.н. binding"и. В итоге программисту, использующему веб-сервис, остается написать что-то типа (псевдокод): NewUser:=TSoapUser.Create("Вася","Пупкин","odmin"); soap.AddUser(NewUser); Автоматическая валидация. Минусов тоже полно:
В качестве примера есть открытый веб-сервис belavia:
Можете вручную создать и послать запрос типа: POST /TimeTable/Service.asmx HTTP/1.1
Host: 86.57.245.235
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://webservices.belavia.by/GetAirportsList"
в ответ придет: HTTP/1.1 200 OK
Date: Mon, 30 Sep 2013 00:06:44 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 4.0.30319
Cache-Control: private, max-age=0
Content-Type: text/xml; charset=utf-8
Content-Length: 2940
ЗЫ Раньше был открыт веб-сервис аэрофлота, но после того как 1C добавили поддержку soap в 8ку, куча 1с-бета-тестеров с успехом положили его. Сейчас что-то там поменяли (адреса не знаю, можно поискать, если интересно). SOAP (Simple Object Access Protocol)
является стандартизированным протоколом передачи сообщений между клиентом и сервером. Обычно он используется совместно с HTTP(S), но может работать и с другими протоколами прикладного уровня (например, SMTP и FTP). Тот факт, что SOAP является протоколом, имеет большое значение для тестирования: нужно изучить сам протокол, «первичные» стандарты и протоколы, на которых он базируется, а также (по мере необходимости) существующие расширения. XML
Более подробно про XML можно узнать на w3schools или codenet (по-русски) . Обязательно обратите внимание на описание namespaces (метод разрешения конфликтов при описании элементов в XML) – в SOAP их использование необходимо. XSD
... Расширения SOAP
Пример использования WS-Security: Все эти расширения – достаточно сложные конструкции, используемые далеко не в каждом SOAP-сервисе; их подробное изучение на начальном этапе освоения тестирования SOAP вряд ли будет актуально. Как вы уже поняли, SOAP – дело серьезное, для работы с ним нужно знать теорию и многочисленные стандарты. На практике такая сложность привела бы к весьма ощутимым трудозатратам (например, нужно было бы каждый раз смотреть схему в блокнотике и слать запросы curl-ом). Поэтому были созданы инструменты, облегчающие работу с SOAP. Редакторы XML / XSD
В моей практике полезными оказались три фичи редакторов: визуализация XSD, генерация XML на основе XSD и валидация XML по XSD. 1. Визуализация XSD
нужна для наглядного представления схемы, позволяющего быстро вычленить обязательные элементы и атрибуты, а также существующие ограничения. Например, для запроса CheckTextRequest обязательным является элемент text, а необязательными – все три атрибута (при этом у атрибута options установлено значение по умолчанию – ноль). Визуализация необходима в том случае, когда типов и ограничений в схеме много. Если вам нужна только она, и вы не хотите платить за специальные редакторы, то можно рассмотреть бесплатные альтернативы (например, JDeveloper). 2. Генерация XML на основе XSD
полезна тогда, когда вы хотите увидеть корректный пример сообщения. Я пользуюсь ей для того, чтобы быстро поэкспериментировать с возможным заполнением сообщения и проверить нюансы работы ограничений. 3.
После использования фичи из пункта 2 полезно провести валидацию XML по XSD
– то есть проверить сообщение на корректность. Вместе фичи 2 и 3 позволяют отлавливать хитрые дефекты в XSD еще тогда, когда сам сервис находится в разработке. Тестирование SOAP практически всегда подразумевает использование SoapUI . Прочитать про использование этого инструмента можно в разных источниках ( , ), но эффективнее всего будет ознакомиться с официальной документацией . Я выделяю 8 условных уровней владения SoapUI: Уровень 1 – умею отправлять запросы
Уровень 2 – умею делать Test Suites и Test Cases
Уровень 3 – умею писать Assertions
Уровень 4 – использую XPath и/или XQuery в Assertions
Уровень 5 – умею писать сложные тесты с помощью специальных шагов
В тест-кейсах может содержаться не только один запрос, но и несколько (к примеру, когда вы хотите эмулировать стандартный сценарий работы пользователя «создать сущность» → «экспортировать сущность»). Между запросами могут находиться другие специальные шаги, например: Уровень 6 – использую скрипты на Groovy
SoapUI позволяет писать скрипты на Groovy в различных местах. Простейший случай – это генерация данных в самом запросе с помощью вставок ${=}. Я постоянно пользуюсь такими вставками: Полноценные скрипты можно использовать в качестве шагов в кейсах и проверках. В какой-то момент вы обнаружите, что сразу несколько специальных шагов из пятого уровня можно заменить одним скриптом. Уровень 7 – использую MockServices
Уровень 8 – бог SoapUI
Приведу пример того, как выглядит запрос к YandexSpeller API, выполненный с помощью groovy-wslite: import wslite.soap.* Насколько я знаю, высокоуровневых фреймворков (по типу Rest-assured) для тестирования SOAP пока не существует, но недавно появился интересный инструмент – karate . С его помощью можно описывать кейсы для тестирования SOAP и REST в виде сценариев по типу Cucumber / Gherkin . Для многих тестировщиков обращение к karate будет идеальным решением, ведь такие сценарии по сложности написания и поддержки кейсов будут лежать где-то посередине между использованием SoapUI и написанием собственного фреймворка для тестирования SOAP. Вряд ли вам когда-либо захочется тестировать SOAP просто так, для себя (как могло бы получиться с REST-ом). Это тяжеловесный протокол, который используется в серьезных корпоративных решениях. Но его тяжеловесность одновременно является подарком тестировщику: все используемые технологии стандартизированы, имеются качественные инструменты для работы. От тестировщика требуется лишь желание их изучить и использовать. Давайте соберем воедино тот самый чек-лист необходимых навыков для тестировщика. Итак, если вы только начинаете тестировать SOAP сервисы, вам нужно знать и уметь использовать: Как видите, основной упор приходится на изучение стандартов, в SoapUI достаточно просто уметь выполнять запросы. По мере погружения в тестирование SOAP перед вам будут возникать задачи, которые потребуют уже более серьезных навыков и знаний, но не стоит пытаться изучить всё и сразу. Гораздо важнее последовательность в повышении уровня сложности выполняемых задач. Следуя этой рекомендации, в один прекрасный момент вы поймете, что стали хорошим специалистом в этой области!Пишем SOAP клиент-серверное приложение на PHP
Так случилось, что в последнее время я стал заниматься разработкой веб-сервисов. Но сегодня топик не обо мне, а о том, как нам написать свой XML Web Service основанный на протоколе SOAP 1.2.
Как вы могли догадаться, вся магия будет твориться с использованием PHP и встроенных классов SoapClient и SoapServer. В качестве кролика у нас будет выступать сервис по отправке sms-сообщений.1 Постановка задачи
1.1 Границы
В начале предлагаю разобраться с тем результатом, которого мы достигнем в конце топика. Как было объявлено выше, мы будем писать сервис по отправке sms-сообщений, а если еще точнее, то к нам будут поступать сообщения из разных источников по протоколу SOAP. После чего, мы рассматрим в каком виде они приходят на сервер. Сам процесс постановки сообщений в очередь для их дальнейшей отправки провайдеру, к сожалению, выходит за рамки данного поста по многим причинам.1.2 Какими данными будем меняться?
Отлично, с границами мы определились! Следующий шаг, который необходимо сделать – решить какими данными мы будем обмениваться между сервером и клиентом. На эту тему предлагаю долго не мудрить и сразу для себя ответить на главные вопросы:
Что-то мне подсказывает, что для этого необходимо посылать следующее:
В принципе, двух этих характеристик достаточно для отправки, но мне сразу представляется случай, как sms-ка с поздравлением о дне рождения приходит вам в 3 часа утра, или 4! В этот момент я буду всем очень благодарен за то, что про меня не забыли! Поэтому, мы также будем посылать на сервер и
Следующее, что я бы хотел отправлять на сервер, так это
Данный параметр не является обязательным, но он может нам очень сильно пригодиться в случае, если быстро понадобится сказать боссу о том, скольких из наших клиентов мы «обрадовали» своим известием, а также нарисовать какую-нибудь красивую статистику на этот счет.2 С чем есть SOAP?
Вообще, изначально я не планировал ничего писать о том, что такое SOAP и хотел ограничиться ссылками на сайт w3.org с нужными спецификациями, а также ссылками на Wikipedia. Но в самом конце решил написать коротенькую справочку об этом протоколе.
Как видно, данный файл и есть весь веб-сервис. Указав в клиенте адрес WSDL-файла мы будем знать об любом веб-сервисе все! В результате, нам не надо абсолютно ничего знать о том, где расположен сам веб-сервис. Достаточно знать адрес расположения его WSDL-файла! Скоро мы узнаем, что не так страшен SOAP как его малюют (с) русская пословицы.3 Введение в XML-Schema
Теперь мы много чего знаем о то, что такое SOAP, что находится у него внутри и имеем обзорное представление о том, какой стек технологий его окружает. Поскольку, прежде всего SOAP представляет собой способ взаимодействия между клиентом и сервером, и в качестве транспорта для него используется язык разметки XML, то в данном разделе мы немного разберемся каким образом происходит автоматическая валидация данных посредством XML-схем.
Что-то очень простое, у чего внутри нет расширений. Их антиподом являются сложные комплексные типы. Самый простой пример комплексного типа, который приходит всем в голову – объекты. Например, книга. Книга состоит из свойств: автор
, название
, цена
, ISBN номер
и т.д. И эти свойства, в свою очередь, могут быть как простыми типами, так и комплексными. И задача XML-схемы это описать.
Схема нашего комплексного типа будет выглядеть следующим образом:
Эта запись читается следующим образом: у нас есть переменная «message
» типа «Message
» и есть комплексный тип с именем «Message
», который состоит из последовательного набора элементов «phone
» типа string
, «text
» типа string
, «date
» типа dateTime
, «type
» типа decimal
. Эти типы простые и уже определены в описании схемы. Поздравляю! Мы только что написали нашу первую XML-схему!
Схема для такого комплексного типа будет выглядеть так:
В первом блоке идет знакомое нам декларирование комплексного типа «Message
». Если вы заметили, то в каждом простом типе, входящем в «Message
», были добавлены новые уточняющие атрибуты «minOccurs
» и «maxOccurs
». Как не трудно догадаться из названия, первый (minOccurs
) сообщает о том, что в данной последовательности должно быть минимум по одному элементу типа «phone
», «text
», «date
» и «type
», в то время как следующий (maxOccurs
) атрибут нам декларирует, что таких элементов в нашей последовательности максимум по-одному. В результате, когда мы пишем свои схемы для каких-либо данных, нам предоставляется широчайший выбор по их настройке!4 Пишем свой WSDL
Вы помните о том, что WSDL и есть наш веб-сервис? Надеюсь, что помните! Как мы его напишем, так на нем наш маленький веб-сервис и поплывет. Поэтому, предлагаю не халтурить.
Но на практике, я обычно отправлял посредством PHP HTTP-заголовок«text/xml
»:
и все прекрасно работало!
Обычно, WSDL состоит из 4-5 основных блоков. Самый первый блок – определение веб-сервиса или другими словами – точки входа.
Здесь написано, что у нас есть сервис, который называется – «SmsService
». В принципе, все имена в WSDL-файле могут быть вами изменены на какие только пожелаете, т.к. они не играют абсолютно никакой роли.
Для этого перечисляется какие операции и в каком виде у будут вызываться. Т.е. для порта «SmsServicePort
» определена привязка под именем «SmsServiceBinding
», которая имеет тип вызова «rpc
» и в качестве протокола передачи (транспорта) используется HTTP. Т.о., мы здесь указали, что будем осуществлять RPC вызов поверх HTTP. После этого мы описываем какие процедуры (operation
) поддерживаются в веб-сервисе. Мы будем поддерживать всего одну процедуру – «sendSms
». Через эту процедуру будут отправляться на сервер наши замечательные сообщения! После того, как была объявлена процедура, необходимо указать в каком виде будут передаваться данные. В данном случае указано, что будут использоваться стандартные SOAP-конверты.
Для этого мы указываем, что наша привязка («binding») имеет тип «SmsServicePortType
» и в элементе «portType
» с одноименным типу именем указываем привязку процедур к сообщениям. И так, входящее сообщение (от клиента к серверу) будет называться «sendSmsRequest
», а исходящее (от сервера к клиенту) «sendSmsResponse
». Как и все имена в WSDL, имена входящих и исходящих сообщения – произвольные.
Для этого мы добавляем элементы «message
» с именами «sendSmsRequest
» и «sendSmsResponse
» соответственно. В них мы указываем, что на вход должен прийти конверт, структура которого соответствует типу данных «Request
». После чего с сервера возвращается конверт содержащий тип данных – «Response
».
Можно нас поздравить! Наш первый WSDL был написан! И мы еще на один шаг приблизились к достижению поставленной цели.
Далее мы разберемся с тем, что нам предоставляет PHP для разработки собственных распределенных приложений.5 Наш первый SOAP-сервер
Ранее я писал, что для создания SOAP-сервера на PHP мы будем использовать встроенный класс SoapServer. Для того, чтобы все дальнейшие действия происходили также как и у меня, вам понадобиться немного подкрутить свой PHP. Если быть еще точнее, то необходимо убедиться, что у вас установлено расширение «php-soap». Как его поставить на ваш веб-сервере лучше всего прочитать на официальном сайте PHP (см. список литературы).
То, что находится выше строчки с функцией «ini_set», надеюсь, что объяснять не надо. Т.к. там определяется какие HTTP-заголовки мы будем отправлять с сервера клиенту и настраивается окружение. В строчке с «ini_set» мы отключаем кеширование WSDL-файла для того, чтобы наши изменения в нем сразу же вступали в действие на клиенте.
На этом этапе получившийся сервер нас должен устроить полностью, т.к. поступающие к нему конверты мы можем логировать и потом спокойно анализировать приходящие данные. Для того, чтобы мы могли что-либо получать на сервер, нам необходим клиент. Поэтому давайте им и займемся!6 SOAP-клиент на подходе
Прежде всего нам надо создать файл, в котором будем писать клиент. Как обычно, мы его создадим в корне хоста и назовем «client.php
», а внутри напишем следующее:
Опишем наши объекты. Когда мы писали WSDL в нем для входящего на сервер конверта описывались три сущности: Request
, MessageList
и Message
. Соответственно классы Request
, MessageList
и Message
являются отражениями этих сущностей в нашем PHP-скрипте.
Давайте запусти и посмотрим что-же у нас наконец-то получилось!
И это замечательно, т.к. теперь мы точно знаем о том, что наш сервер работает и не просто работает, но еще и может возвращать на клиент какие-то значения!
Это и есть конверт. Теперь вы знаете как он выглядит! Но постоянно на него любоваться нам вряд ли будет интересно, поэтому давайте десереализуем объект из лог-файла и посмотрим все ли у нас хорошо:
Как видим, объект десериализовался правильно, с чем я нас всех хочу поздравить! Далее нас ждет что-то более интересно! А именно – мы будем отправлять клиентом на сервер не одно sms-сообщение, а целую пачку (если быть точнее, то целых три)!7 Отправляем сложные объекты
Давайте подумаем над тем, как же нам передать целую пачку сообщений на сервер в одном пакете? Наверно, самым простым способом будет организация массива внутри элемента messageList! Давайте это сделаем:
В наших логах числится, что пришел следующий пакет от клиента:
Что за ерунда, скажете вы? И будете правы в некотором смысле, т.к. только что мы узнали о том, что какой объект ушел от клиента, то абсолютно в том же виде он пришел к нам на сервер в виде конверта. Правда, sms-сообщения сериализовались в XML не так, как нам было необходимо – они должны были быть обернуты в элементы message
, а не в Struct
. Теперь посмотрим в каком виде приходит такой объект в метод sendSms
:
Что нам дает это знание? Только то, что выбранный нами путь не является верным и мы не получили ответа на вопрос – «Как нам на сервере получить правильную структуру данных?». Но я предлагаю не отчаиваться и попробовать привести наш массив к типу объект
:
В этом случае, нам придет уже другой конверт:
Пришедший в метод sendSms
объект имеет следующую структуру:
Как по мне, то «от перемены мест слагаемых – сумма не меняется» (с). Что BOGUS
, что Struct
– цель нами до сих пор не достигнута! А для ее достижения нам необходимо сделать так, чтобы вместо этих непонятных названий отображалось наше родное message
. Но как этого добиться, автору пока не известно. Поэтому единственное, что мы можем сделать – избавить от лишнего контейнера. Другими словами, мы сейчас сделаем так, чтобы вместо message
стал BOGUS
! Для этого изменим объект следующим образом:
Вдруг нам повезет и из схемы подтянется правильное название? Для этого посмотрим на пришедший конверт:
Да, чуда не произошло! BOGUS
– не победим! Пришедший в sendSms
объект в этом случае будет выглядеть следующим образом:
Как говорится – «Почти»! На этой (немного печальной) ноте предлагаю потихонечку закругляться и сделать некоторые для себя выводы.8 Заключение
Наконец-то мы добрались сюда! Давайте определимся с тем, что вы теперь умеете делать:
Также, мы сделали для себя некоторые открытия в ходе нашего небольшого исследования:
ЗЗЫ Дисклеймер. Рассказал на бытовом уровне. Пинать можно.
Тестирование SOAP с точки зрения техник тестирования ничем принципиально не отличается от работы с другими API, но для его проведения требуются предварительная подготовка (в плане теории протокола) и специальные инструменты для тестирования. В данной статье я хотела бы сформулировать небольшой чек-лист необходимых знаний и навыков, который будет одинаково полезен как тестировщику SOAP (зачастую не представляющему, «за что хвататься» после постановки задачи), так и менеджеру, вынужденному оценивать знания тестировщиков и разрабатывать планы по обучению.Теоретическая база
XML – язык разметки, схожий с HTML. Любое сообщение, отправляемое/получаемое через SOAP, – это XML-документ, в котором данные удобно структурированы и легко читаемы, например:
Не забудь написать статью!
При работе всегда удобно иметь стандартизированное описание возможных XML-документов и проверять их на корректность заполнения. Для этого существует XML Schema Definition (или сокращенно XSD). Две главные фичи XSD для тестировщика – это описание типов данных и наложение ограничений на возможные значения. Например, элемент из предыдущего примера можно сделать необязательным для заполнения и ограничить его размер 255 символами с помощью XSD:
...
В работе вам также могут встретиться различные «расширения» SOAP – стандарты типа WS-*
. Одним из самых распространенных является WS-Security позволяющий работать с шифрованием и электронными подписями. Нередко вместе с ним применяется WS-Policy, с помощью которого можно управлять правами на использование вашего сервиса.
Инструменты
Хороший тестировщик начинает тестирование еще на стадии написания документации, поэтому для проверки схем удобно использовать специальные редакторы. Два самых известных – Oxygen (кроссплатформенный) и Altova (только для Windows); оба они являются платными. Это очень мощные программы, которыми активно пользуются аналитики при описании сервисов.Инструмент тестирования – SoapUI
Научитесь создавать проект на основе WSDL. SoapUI может сгенерировать все необходимые запросы для вас; вам останется лишь проверить правильность их заполнения и нажать кнопочку «Send». После выработки навыков создания корректных запросов вы должны овладеть искусством формирования некорректных запросов, вызывающих появление ошибок.
Начните делать мини-автотесты. Тест-комплекты и тест-кейсы позволяют создавать сценарии тестирования API, подготавливать данные для запросов и автоматически проверять полученный ответ на соответствие ожидаемому. На первых порах их можно использовать просто как коллекции запросов. Например, если вы завели дефект и хотите быстро проверить его после фикса, можно выделить отдельный тест-комплект конкретно под запросы-дефекты.
После освоения тест-кейсов вам будет полезно научиться делать их автоматически проверяемыми. После этого вам уже не нужно будет искать «глазами» информацию об ответе: при наличии автоматической проверки кейсы будут помечаться зеленым (если проверка пройдена) или красным (если не пройдена). SoapUI предоставляет большой набор возможных проверок (assertions), но самые удобные и простые – это Contains и Not Contains. С их помощью можно проверить факт наличия конкретного текста в полученном ответе. Эти проверки также поддерживают поиск с помощью регулярных выражений.
Для тех, кто немного знаком с UI с помощью Selenium, язык XPath – знакомая вещь. Грубо говоря, XPath позволяет искать элементы в XML-документе. XQuery – похожая технология, которая может использовать XPath внутри себя; этот язык гораздо мощнее, он напоминает SQL. Оба эти языка можно использовать в Assertions. Проверки с их помощью получаются более прицельными и стабильными, поэтому ваши кейсы будут пользоваться большим доверием.
SoapUI на основе WSDL может генерировать Mock-объекты . Mock-объект – это простейшая симуляция сервиса. С помощью «моков» можно начать писать и отлаживать тест-кейсы еще до того, как сервис реально будет доступен для тестирования. Также их можно использовать в качестве «заглушек» для временно недоступных сервисов.
Вы знаете разницу между платной и бесплатной версиями SoapUI и используете SoapUI API в коде. Вы используете плагины и запускаете выполнение кейсов через командную строку и/или CI. Ваши тест-кейсы просты и легко поддерживаются. В общем, вы «съели собаку» на этом инструменте. Я бы с радостью пообщалась с тем, кто освоил SoapUI на таком уровне. Если вы являетесь таковым – отпишитесь в комментариях!Тестирование с помощью языков программирования
def client = new SOAPClient("http://speller.yandex.net/services/spellservice?WSDL")
def response = client.send(SOAPAction: "http://speller.yandex.net/services/spellservice/checkText") {
body {
CheckTextRequest("lang": "ru", "xmlns":"http://speller.yandex.net/services/spellservice") {
text("ошипка")
}
}
}
assert "ошибка" == response.CheckTextResponse.SpellResult.error.s.text()
assert "1" == [email protected]()Заключение