Использование WireMock с веб-службами SOAP в Java
Я совершенно новичок в WireMock.
до сих пор я использовал макет ответов, используя SOAPUI. Мой случай использования прост:
просто запуск SOAP XML-запросов к различным конечным точкам (http://localhost:9001/endpoint1) и получение консервированного ответа XML. Но MockWrire должен быть развернут как автономная служба на выделенном сервере, который будет действовать в центральном месте, откуда будут подаваться фиктивные ответы.
просто хотел некоторые начальные предложения. Как я вижу, WireMock больше подходит для веб-сервисов REST. Поэтому мои сомнения таковы:
1) мне нужно развернуть его на веб-сервере или контейнере java, чтобы действовать как всегда с автономной службой. Я читал, что вы можете просто отключиться, используя
java -jar mockwire.jar --port [port_number]
2)Нужно ли использовать API MockWire? Мне нужно сделать классы для моего прецедента? В моем случае запросы будут запускаться через тестовые случаи JUnit для насмешек.
3) Как мне добиться простой шаблон URL-адреса? Как указано выше, мне просто нужно просто издеваться над i.e получить ответ при запросе http://localhost:9001/endpoint1
4) Есть ли лучшая/более простая структура для моего usecase? Я читал о Mockable, но у него есть ограничения для 3 членов команды и демо-домена в свободном уровне.
3 ответов
Я создатель WireMock.
я использовал WireMock для макета коллекции интерфейсов SOAP в клиентском проекте совсем недавно, поэтому я могу подтвердить, что это возможно. Что касается того, лучше или хуже, чем SOAP UI, я бы сказал, что есть определенные недостатки, но с некоторыми компромиссами. Основным преимуществом является относительная простота развертывания и программного доступа / конфигурации, а также поддержка таких вещей, как HTTPS и низкоуровневая инъекция ошибок. Тем не менее, вам нужно сделать немного больше работы, чтобы анализировать и генерировать полезные нагрузки SOAP - он не будет делать генерацию кода/заглушки из WSDL, как SOAP UI.
мой опыт заключается в том, что такие инструменты, как SOAP UI, позволят вам начать работу быстрее, но, как правило, приводят к более высоким расходам на обслуживание в долгосрочной перспективе, когда ваш набор тестов выходит за рамки тривиального.
чтобы обратиться к вашим точкам в свою очередь: 1) Если вы хотите, чтобы ваши насмешки запускались на сервере где-то, самый простой способ сделать это-запустить автономную банку, как вы описали. Я бы не советовал пробовать чтобы развернуть его в контейнер-этот параметр действительно существует только тогда, когда нет альтернативы.
однако, если вы просто хотите запустить интеграционные тесты или полностью автономные функциональные тесты, я бы предложил использовать правило JUnit. Я бы сказал, что это только хорошая идея запустить его в выделенном процессе, если a) вы подключаете к нему другие развернутые системы или b) вы используете его с языка, отличного от JVM.
2) вам нужно настроить его одним из 3 способов 1) API Java, 2) JSON через HTTP или 3) файлы JSON. 3) вероятно, ближе всего к тому, к чему вы привыкли с SOAP UI.
3) см.http://wiremock.org/stubbing.html для множества примеров stubbing, использующих как JSON, так и Java. Поскольку SOAP имеет тенденцию привязываться к фиксированным URL-адресам конечных точек, вы, вероятно, хотите urlEqualTo(...)
. Когда я тушил мыло в прошлом, я имел тенденцию к совпадению XML по всему телу запроса (см. http://wiremock.org/stubbing.html#xml-body-matching). Я бы предложил инвестировать в написание нескольких Java-построителей для создания необходимого XML-кода тела запроса и ответа.
4) Макет Сервера и Бетамакс являются зрелыми альтернативами WireMock, но AFAIK они не предлагают более явной поддержки SOAP.
Я опаздываю на три года на эту вечеринку, но мне потребовалось некоторое время, чтобы проработать ту же проблему, поэтому я подумал, что это достойно документирования моего решения в качестве ответа, чтобы это могло спасти кого-то еще от головной боли вручную иметь дело с полезными нагрузками мыла с нуля.
Я сделал разумное исследование, пытаясь решить эту проблему для моего набора интеграционных тестов. Пробовал все виды вещей, включая пользовательские серверы CXF, SOAP-UI, библиотеку CGLIB, которая заменяет реальный клиент в тестовом контексте.
Я закончил использование WireMock с пользовательские сопоставления запросов для обработки всех SOAP
-yness.
суть его была классом, который обрабатывал unmarshaling запросов SOAP и маршалинг ответов SOAP, чтобы обеспечить удобную оболочку для тестирования авторов, которые требовали только генерируемых объектов JAXB и никогда не должны были беспокоиться о деталях SOAP.
ответ Маршалинг
/**
* Accepts a WebService response object (as defined in the WSDL) and marshals
* to a SOAP envelope String.
*/
public <T> String serializeObject(T object) {
ByteArrayOutputStream byteArrayOutputStream;
Class clazz = object.getClass();
String responseRootTag = StringUtils.uncapitalize(clazz.getSimpleName());
QName payloadName = new QName("your_namespace_URI", responseRootTag, "namespace_prefix");
try {
JAXBContext jaxbContext = JAXBContext.newInstance(clazz);
Marshaller objectMarshaller = jaxbContext.createMarshaller();
JAXBElement<T> jaxbElement = new JAXBElement<>(payloadName, clazz, null, object);
Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
objectMarshaller.marshal(jaxbElement, document);
SOAPMessage soapMessage = MessageFactory.newInstance().createMessage();
SOAPBody body = soapMessage.getSOAPPart().getEnvelope().getBody();
body.addDocument(document);
byteArrayOutputStream = new ByteArrayOutputStream();
soapMessage.saveChanges();
soapMessage.writeTo(byteArrayOutputStream);
} catch (Exception e) {
throw new RuntimeException(String.format("Exception trying to serialize [%s] to a SOAP envelope", object), e);
}
return byteArrayOutputStream.toString();
}
Запрос Unmarshaling
/**
* Accepts a WebService request object (as defined in the WSDL) and unmarshals
* to the supplied type.
*/
public <T> T deserializeSoapRequest(String soapRequest, Class<T> clazz) {
XMLInputFactory xif = XMLInputFactory.newFactory();
JAXBElement<T> jb;
try {
XMLStreamReader xsr = xif.createXMLStreamReader(new StringReader(soapRequest));
// Advance the tag iterator to the tag after Body, eg the start of the SOAP payload object
do {
xsr.nextTag();
} while(!xsr.getLocalName().equals("Body"));
xsr.nextTag();
JAXBContext jc = JAXBContext.newInstance(clazz);
Unmarshaller unmarshaller = jc.createUnmarshaller();
jb = unmarshaller.unmarshal(xsr, clazz);
xsr.close();
} catch (Exception e) {
throw new RuntimeException(String.format("Unable to deserialize request to type: %s. Request \n %s", clazz, soapRequest), e);
}
return jb.getValue();
}
private XPath getXPathFactory() {
Map<String, String> namespaceUris = new HashMap<>();
namespaceUris.put("xml", XMLConstants.XML_NS_URI);
namespaceUris.put("soap", "http://schemas.xmlsoap.org/soap/envelope/");
// Add additional namespaces to this map
XPath xpath = XPathFactory.newInstance().newXPath();
xpath.setNamespaceContext(new NamespaceContext() {
public String getNamespaceURI(String prefix) {
if (namespaceUris.containsKey(prefix)) {
return namespaceUris.get(prefix);
} else {
return XMLConstants.NULL_NS_URI;
}
}
public String getPrefix(String uri) {
throw new UnsupportedOperationException();
}
public Iterator getPrefixes(String uri) {
throw new UnsupportedOperationException();
}
});
return xpath;
}
в дополнение к этому были некоторые утилиты XPath для заглядывания в полезную нагрузку запроса и просмотра запрошенной операции.
все обработки мыла был fiddliest части, чтобы получить работу. Оттуда он просто создает свой собственный API для дополнения WireMocks. Например
public <T> void stubOperation(String operation, Class<T> clazz, Predicate<T> predicate, Object response) {
wireMock.stubFor(requestMatching(
new SoapObjectMatcher<>(context, clazz, operation, predicate))
.willReturn(aResponse()
.withHeader("Content-Type", "text/xml")
.withBody(serializeObject(response))));
}
и в результате вы заканчиваете с хорошими, постными тестами.
SoapContext context = new SoapContext(...) // URIs, QName, Prefix, ect
context.stubOperation("createUser", CreateUser.class, (u) -> "myUser".equals(u.getUserName()), new CreateUserResponse());
soapClient.createUser("myUser");
- я запускаю сервер wiremock как автономный
-
Я создаю отображение.файл json, поместите в папку "сопоставления" моего макета проекта
{"request": { "url": "/webservicesserver/numberconversion", "method": "POST"}, "response": { "status": 200, "bodyFileName": "response.xml", "headers": { "Server": "Microsoft-IIS/8.0", "Access-Control-Allow-Origin": "http://www.dataaccess.com", "Access-Control-Allow-Methods": "GET, POST", "Connection": "Keep-Alive", "Web-Service": "DataFlex 18.1", "Access-Control-Allow-Headers": "content-type", "Date": "Tue, 26 Jun 2018 07:45:47 GMT", "Strict-Transport-Security": "max-age=31536000", "Cache-Control": "private, max-age=0", "Access-Control-Allow-Credentials": true, "Content-Length": 352, "Content-Type": "application/soap+xml; charset=utf-8" }}}
-
Я создаю xml-файл ответа, помещаю его в папку "_ _ files"
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" > <soap:Body> <m:NumberToDollarsResponse xmlns:m="http://www.dataaccess.com/webservicesserver/"> <m:NumberToDollarsResult>twelve dollars</m:NumberToDollarsResult> </m:NumberToDollarsResponse> </soap:Body> </soap:Envelope>