在Java中与SOAP Web服务一起使用WireMock
我是个新手 到目前为止,我一直在使用SOAPUI模拟响应。我的用例很简单: 只需将soapxml请求发送到不同的端点()并获得固定的XML响应。但是MockWrire必须作为一个独立的服务部署到一个专用的服务器上,该服务器将充当一个中心位置,从那里提供模拟响应 只是想要一些开始的建议。正如我所看到的,WireMock更适合RESTWeb服务。因此,我的疑问是: 1) 我是否需要将其部署到JavaWeb服务器或容器,以充当始终运行独立服务的角色。我读到你可以通过使用在Java中与SOAP Web服务一起使用WireMock,java,web-services,soap,mocking,wiremock,Java,Web Services,Soap,Mocking,Wiremock,我是个新手 到目前为止,我一直在使用SOAPUI模拟响应。我的用例很简单: 只需将soapxml请求发送到不同的端点()并获得固定的XML响应。但是MockWrire必须作为一个独立的服务部署到一个专用的服务器上,该服务器将充当一个中心位置,从那里提供模拟响应 只是想要一些开始的建议。正如我所看到的,WireMock更适合RESTWeb服务。因此,我的疑问是: 1) 我是否需要将其部署到JavaWeb服务器或容器,以充当始终运行独立服务的角色。我读到你可以通过使用 java -jar mockw
java -jar mockwire.jar --port [port_number]
2) 我需要使用MockWire API吗?我需要为我的用例创建类吗?在我的例子中,请求将通过JUnit测试用例触发以进行模拟
3) 如何实现简单的URL模式匹配?如上所述,我只需要简单的模拟,即在请求发出时获得响应
4) 我的用例有更好/更简单的框架吗?我读过Mockable,但它对3名团队成员和免费层中的演示域有限制。我是WireMock的创建者 最近,我在一个客户端项目上使用WireMock模拟了一组SOAP接口,因此我可以证明这是可能的。至于它比soapui好还是坏,我想说有一些明确的优点,但有一些折衷。一个主要好处是部署和编程访问/配置相对容易,并且支持HTTPS和低级故障注入等功能。然而,您需要做更多的工作来解析和生成SOAP有效负载——它不会像SOAP UI那样从WSDL生成代码/存根 我的经验是,像soapui这样的工具可以让您更快地启动,但从长远来看,当您的测试套件超出了琐碎的需求时,往往会导致更高的维护成本 依次阐述你的观点: 1) 如果您想让mock在某个服务器上运行,最简单的方法是运行独立的JAR,如您所述。我建议不要尝试将其部署到容器中—此选项只在没有其他选择时才存在 但是,如果您只想运行集成测试或完全自包含的功能测试,我建议使用JUnit规则。我想说,如果a)您正在将其他部署的系统插入其中,或者b)您正在从非JVM语言使用它,那么在专用进程中运行它才是一个好主意 2) 您需要通过以下三种方式之一进行配置:1)Java API、2)HTTP上的JSON或3)JSON文件。3) 可能最接近您对SOAP UI的习惯 3) 有关使用JSON和Java的大量存根示例,请参阅。由于SOAP倾向于绑定到固定端点URL,您可能需要
urlEqualTo(…)
。当我在过去中断SOAP时,我倾向于在整个请求体上进行XML匹配(请参阅)。我建议投资编写一些Java构建器,以生成所需的请求和响应体XML
4) 和都是WireMock的成熟替代品,但它们没有提供任何更明确的SOAP支持。我参加这次聚会晚了三年多,但是我花了一段时间来解决同一个问题,所以我认为有必要将我的解决方案记录下来作为一个答案,这样就可以避免其他人从头开始手动处理SOAP有效负载的头痛 为了解决我的集成测试套件的这个问题,我做了大量的研究。尝试了各种各样的东西,包括CXF自定义生成的服务器、SOAP-UI、一个受CGLIB影响的库,它在测试上下文中替换了真实的客户机 我最终使用WireMock with来处理所有的
SOAP
-ynes
它的要点是一个类,它处理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();
}
{“请求”:{
“url”:“/WebServiceServer/numberconversion”,
“方法”:“POST”},
“答复”:{
“地位”:200,
“bodyFileName”:“response.xml”,
“标题”:{
“服务器”:“Microsoft IIS/8.0”,
“访问控制允许源”:http://www.dataaccess.com",
“访问控制允许方法”:“获取、发布”,
“连接”:“保持活动状态”,
“Web服务”:“DataFlex 18.1”,
“访问控制允许标头”:“内容类型”,
“日期”:“2018年6月26日星期二07:45:47 GMT”,
“严格的运输安全”:“最大年龄=31536000”,
“缓存控制”:“专用,最大年龄=0”,
“访问控制允许凭据”:true,
“内容长度”:352,
“内容类型”:“应用程序/soap+xml;字符集=utf-8”
}}}
十二美元
请您解释一下,我如何指定“\u文件”和“映射”文件夹使用的相对/绝对路径?我通过maven设置了mockwire依赖项,并创建了一个简单的servlet来执行
wireMockServer.start()初始化()
。我猜with rootdirectory()
或使用files underdirectory()
withWireMockConfiguration
应该有效?我通过创建自定义文件源
并将其传递到WireMockConfiguration
解决了这个问题。谢谢。@Tom你在StackOverflow方面不是很多产,但我只是想说WireMock是一个很棒的工具-非常感谢!Tom,你能提供一些例子吗?@RafalEnden我的回答中包含了所有需要工作的例子的代码。太棒了,谢谢分享!我申请将其添加到WireMock。我有个问题。我有肥皂1.2。我已经创建了端点,但它给了我一个错误:一个so
/**
* 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;
}
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");