Web Services 在Java中使用WireMock和SOAP Web服务

mbskvtky  于 2022-11-15  发布在  Java
关注(0)|答案(3)|浏览(228)

我对WireMock完全是新手。
到目前为止,我一直在使用SOAPUI模拟响应。我的用例很简单:
只是向不同的端点(http://localhost:9001/endpoint1)发出SOAP XML请求,并返回固定的XML响应。但MockWrire必须作为独立服务部署到专用服务器上,该服务器将充当提供模拟响应的中心位置。
只是想得到一些初步的建议。正如我所看到的,WireMock更适合REST Web服务。所以我的疑问是:
1)我是否需要将其部署到一个java web服务器或容器中,以始终运行独立服务?

java -jar mockwire.jar --port [port_number]

2)我需要使用MockWire API吗?我需要为我的用例创建类吗?在我的例子中,请求将通过JUnit测试用例触发以进行模拟。
3)如何实现简单的URL模式匹配?如上所述,我只需要简单的模拟,即在向http://localhost:9001/endpoint1发出请求时获得响应
4)有没有更好/更容易的框架为我的用例?我读了关于Mockable,但它有3个团队成员的限制和演示域在自由层。

j7dteeu8

j7dteeu81#

我是WireMock的创造者。
我最近使用WireMock模拟了一个客户端项目上的SOAP接口集合,因此我可以证明这是可能的。至于它比SOAP UI更好还是更差,我想说它有一些明确的优点,但也有一些缺点。一个主要的优点是部署和编程访问/配置相对容易,并支持HTTPS和低级错误注入之类的东西。然而,您需要做更多的工作来解析和生成SOAP有效负载-它不会像SOAPUI那样从WSDL生成代码/存根。
我的经验是,像SOAP UI这样的工具会让您更快地开始,但是当您的测试套件增长到超出微不足道的程度时,从长远来看,往往会导致更高的维护成本。
依次阐述您的观点:1)如果你想在某个服务器上运行你的模拟,最简单的方法就是运行你所描述的独立的JAR。我建议不要尝试将它部署到容器中--这个选项只在没有其他选择的情况下才存在。
然而,如果您只想运行集成测试或完全自包含的功能测试,我建议使用JUnit规则。我认为只有在以下情况下,在专用进程中运行它才是一个好主意:a)您将其他部署的系统插入到它中,或者B)您从非JVM语言中使用它。
2)您需要通过以下三种方式之一来配置它:1)Java API,2)HTTP上的JSON,或者3)JSON文件。3)可能最接近您使用SOAP UI时所使用的方式。
3)请参阅http://wiremock.org/stubbing.html,了解大量使用JSON和Java的存根示例。由于SOAP倾向于绑定到固定端点URL,因此您可能需要urlEqualTo(...)。过去我对SOAP进行存根时,倾向于在整个请求主体上进行XML匹配(请参阅http://wiremck.org/stubbing.html#xml-body-matching)。我建议投资编写一些Java构建器,以发出所需的请求和响应主体XML。
4)Mock ServerBetamax都是WireMock的成熟替代品,但AFAIK不提供任何更显式的SOAP支持。

cvxl0en2

cvxl0en22#

我参加这个聚会晚了三年多,但我花了一段时间来解决同样的问题,所以我认为值得记录我的解决方案作为答案,这样可以保存其他人从头开始手动处理SOAP有效负载的头痛。
我做了一个合理的研究,试图解决这个问题,我的集成测试套件。尝试了各种各样的东西,包括CXF自定义生成的服务器,SOAP-UI,一个CGLIB影响的库,取代了测试上下文中的真实的客户端。
我最终使用WireMock和自定义请求匹配器来处理所有的SOAP-yness。
它的要点是一个类,用于处理SOAP请求的解组和SOAP响应的封送,以便为测试作者提供一个方便的 Package 器,这些作者只需要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();
}

请求取消封送

/**
 * 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实用程序,用于查看请求负载并查看正在请求的操作。
所有的SOAP处理都是工作中最复杂的部分。

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");
t9eec4r0

t9eec4r03#

1.我将Wirerock服务器作为独立服务器运行
1.我创建了一个mapping.json文件,放在我的模拟项目“mappings”文件夹中
{"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" }}}
1.我创建了一个响应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>

相关问题