Utilisation de WireMock avec les services web SOAP en Java

je suis totalement nouveau pour WireMock.

Jusqu'à présent, J'ai utilisé des réponses simulées en utilisant SOAPUI. Mon cas d'utilisation est simple:

Juste tir SOAP XML demandes de différents paramètres (http://localhost:9001/endpoint1) et obtenir la réponse XML mise en boîte de retour. Mais MockWrire doit être déployé en tant que service autonome sur un serveur dédié qui agira comme un emplacement central d'où les réponses simulées seront servies.

voulais Juste quelques suggestions. Comme je peux le voir WireMock est plus adapté vers les services REST web. Donc mes doutes sont:

1) est-ce que je dois le déployer sur un serveur web java ou un conteneur pour agir comme toujours en exécutant un service autonome? J'ai lu que vous pouvez simplement spin-off à l'aide de

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

2) dois-je utiliser des API MockWire? Dois-je donner des cours pour mon étui? Dans mon cas, les requêtes seront déclenchées via les cas de test JUnit pour moquerie.

3) Comment réaliser simple Correspondance des URL? Comme indiqué ci-dessus, j'ai juste besoin de moquerie simple I. e obtenir une réponse lorsque la demande est faite à http://localhost:9001/endpoint1

4) y a-t-il un cadre meilleur/plus facile pour mon usecase? J'ai lu à propos de Mockable mais il a des restrictions pour 3 membres de l'équipe et demo domaine en free tier.

8
demandé sur Anurag 2016-03-13 21:46:12

3 réponses

je suis le créateur de WireMock.

J'ai utilisé WireMock pour simuler une collection D'interfaces SOAP sur un projet client très récemment, donc je peux attester que c'est possible. Quant à savoir si c'est mieux ou pire que SOAP UI, je dirais qu'il y a des avantages certains, mais avec quelques compromis. Un avantage majeur est la facilité relative de déploiement et d'accès/configuration programmatique, et le support pour des choses comme les HTTPS et l'injection de défauts de bas niveau. Cependant, vous devez faire un peu plus de travail pour analyser et générer des charges utiles SOAP - il ne fera pas de génération de code / talon à partir de WSDL comme SOAP UI le fera.

mon expérience est que les outils comme SOAP UI vous permettra de commencer plus rapidement, mais ont tendance à entraîner des coûts de maintenance plus élevés à long terme lorsque votre suite de test se développe au-delà de trivial.

pour répondre À vos points de tourner: 1) Si vous voulez que vos moqueurs s'exécutent sur un serveur quelque part, la façon la plus simple de faire cela est d'exécuter le JAR autonome comme vous l'avez décrit. Je vous conseille de ne pas essayer à la déployer dans un conteneur - cette option n'existe que quand il n'y a pas d'alternative.

cependant, si vous voulez juste exécuter des tests d'intégration ou des tests fonctionnels totalement autonomes, je vous suggère d'utiliser la règle JUnit. Je dirais que ce n'est qu'une bonne idée de l'exécuter dans un processus dédié si a) vous y branchez d'autres systèmes déployés, ou b) vous l'utilisez à partir d'un langage non-JVM.

2) vous devez le configurer de l'une des 3 façons suivantes: 1) L'API Java, 2) JSON sur HTTP, ou 3) fichiers JSON. 3) est probablement plus proche de ce à quoi vous êtes habitué avec SOAP UI.

3) Voir http://wiremock.org/stubbing.html pour beaucoup de cogner les exemples à l'aide de deux JSON et Java. Puisque SOAP a tendance à se lier à des URLs de fin de point fixes, vous voulez probablement urlEqualTo(...). Quand j'ai entaillé SOAP dans le passé, j'ai eu tendance à faire correspondre XML sur l'ensemble du corps de la requête (voir http://wiremock.org/stubbing.html#xml-body-matching). Je suggère d'investir dans écrire quelques constructeurs Java pour émettre le XML de corps de requête et de réponse dont vous avez besoin.

4)Faux Serveur et Betamax sont deux alternatives matures à WireMock, mais AFAIK ils n'offrent pas de support SOAP plus explicite.

22
répondu Tom 2016-11-09 20:42:14

je suis plus de trois ans en retard à cette fête, mais il m'a fallu un certain temps pour travailler à travers le même problème donc j'ai pensé qu'il valait la peine de documenter ma solution comme une réponse afin qu'il pourrait sauver quelqu'un d'autre le mal de tête de traiter manuellement les charges utiles de SOAP à partir de zéro.

j'ai fait une recherche raisonnable pour essayer de résoudre ce problème pour ma suite de test d'intégration. Essayé toutes sortes de choses, y compris CXF serveurs générés sur mesure, SOAP-UI, une bibliothèque influencée par CGLIB qui remplace le un vrai client dans un contexte de test.

j'ai fini par utiliser WireMock avec personnaliser demande de rapprochement pour répondre à toutes les SOAP-yness.

l'essentiel en était une classe qui manipulait le désembuage des requêtes SOAP et le regroupement des réponses SOAP afin de fournir un emballage pratique pour tester les auteurs qui n'avaient besoin que d'objets générés par JAXB et n'avaient jamais à se préoccuper des détails de SOAP.

Réponse Marshaling

/**
 * 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();
}

Demande Désordonnancement

/**
 * 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;
}

en plus de cela, il y avait quelques utilitaires XPath pour jeter un coup d'oeil à la charge utile de la requête et pour voir quelle opération était demandée.

tout le maniement du savon a été la partie la plus difficile à travailler. À partir de là, il suffit de créer votre propre API pour compléter WireMocks. Par exemple,

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))));
}

et en conséquence, vous vous retrouvez avec un bon, lean tests.

SoapContext context = new SoapContext(...) // URIs, QName, Prefix, ect
context.stubOperation("createUser", CreateUser.class, (u) -> "myUser".equals(u.getUserName()), new CreateUserResponse());

soapClient.createUser("myUser");
10
répondu markdsievers 2017-11-09 13:12:14
  1. j'ai l'exécution de la wiremock serveur de manière autonome
  2. je crée un mapping.JSON file, mettez dans mon dossier mock project '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" }}}

  3. je crée un fichier de réponse xml, mettez - le dans le dossier' _ _ 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>

0
répondu Jin 2018-06-26 07:59:37