2017-09-22 9 views
1

J'essaie de générer un pacte entre 2 de nos services en utilisant pact-JVM. Mais quand j'essaie d'exécuter la classe Java, j'obtiens cette exception.pact-jvm: comment résoudre au.com.dius.pact.consumer.PactMismatchesException

1) Je soupçonne que quelque chose ne va pas avec le corps du Pacte, est-ce exact? Il y a un paramètre 'message' supplémentaire dans le corps JSON du PactDslWithProvider, mais dans la méthode runTest1(), je n'équivaut que les listes et quand j'inspecte les résultats, ils sont identiques à moi. 2) Est-il correct de fournir l'URL réelle du fournisseur dans la méthode runTest1()? (Le fournisseur est déjà en place)

au.com.dius.pact.consumer.PactMismatchesException: The following requests were not received: 
method: GET 
path: /devices/v1 
query: [externalId:[0942dc67-35de-44f7-a061-743f59436a98]] 
headers: [:] 
matchers: MatchingRules(rules=[:]) 
generators: Generators(categories={}) 
body: OptionalBody(state=MISSING, value=null) 

Ci-dessous est ma classe Java

public class PactForDevice { 
    Map<String, String> headers = MapUtils.putAll(new HashMap<String, String>(), new String[]{"Content-Type", "application/json;charset=UTF-8"}); 

@Rule 
public PactProviderRuleMk2 provider = new PactProviderRuleMk2("device-service-m", this); 

@Pact(consumer = "device-r", provider = "device-service-m") 
public RequestResponsePact createFragment(PactDslWithProvider builder) { 

    return builder 
      .given("Device M details") 
      .uponReceiving("retrieving Device details") 
      .path("/devices/v1") 
      .method("GET") 
      .query("externalId=0942dc67-35de-44f7-a061-743f59436a98") 
      .willRespondWith() 
      .headers(headers) 
      .status(200) 
      .body("{" + 
        "\"data\": [,\n " + 
        "{ \n" + 
        " \"dateRegistered\": \"2017-07-13T11:10:51.000+12:00\",\n" + 
        " \"alias\": \"\",\n" + 
        " \"id\": \"a02b14ee72192ab3\",\n" + 
        " \"description\": \"Samsung SM-G930F\",\n" + 
        " \"title\": \"a02b14ee72192ab3\",\n" + 
        " \"externalId\": \"0942dc67-35de-44f7-a061-743f59436a98\"\n" + 
        "},\n" + 
        "{\n" + 
        " \"dateRegistered\": \"2017-07-13T10:45:51.000+12:00\",\n" + 
        " \"alias\": \"\",\n" + 
        " \"id\": \"a41c3af56ec35874\",\n" + 
        " \"description\": \"Samsung SM-T819\",\n" + 
        " \"title\": \"a41c3af56ec35874\",\n" + 
        " \"externalId\": \"0942dc67-35de-44f7-a061-743f59436a98\"\n" + 
        " },\n" + 
        " {\n" + 
        " \"dateRegistered\": \"2017-07-13T10:45:31.000+12:00\",\n" + 
        " \"alias\": \"\",\n" + 
        " \"id\": \"bd2b027bbd0a2f17\",\n" + 
        " \"description\": \"Samsung SM-A320Y\",\n" + 
        " \"title\": \"bd2b027bbd0a2f17\",\n" + 
        " \"externalId\": \"0942dc67-35de-44f7-a061-743f59436a98\"\n" + 
        " }\n" + 
        "],\n" + 
        " \"message\": \"3 devices found for the user 0942dc67-35de-44f7-a061-743f59436a98\"\n" + 
        "}") 
      .toPact(); 
} 

@PactVerification("device-service-m") 
@Test 
@JsonIgnoreProperties(ignoreUnknown = true) 
public void runTest1() throws IOException { 

    final GetDevicesResponse deviceResponse = new GetDevicesResponse(); 

    final List<Device> deviceList = new ArrayList<>(); 
    Device dev = new Device(); 
    dev.withDateRegistered("2017-07-13T11:10:51.000+12:00"); 
    dev.withAlias(""); 
    dev.withId("a02b14ee72192ab3"); 
    dev.withDescription("Samsung SM-G930F"); 
    dev.withTitle("a02b14ee72192ab3"); 
    dev.withExternalId("0942dc67-35de-44f7-a061-743f59436a98"); 
    deviceList.add(dev); 

    Device dev1 = new Device(); 
    dev1.withDateRegistered("2017-07-13T10:45:51.000+12:00"); 
    dev1.withAlias(""); 
    dev1.withId("a41c3af56ec35874"); 
    dev1.withDescription("Samsung SM-T819"); 
    dev1.withTitle("a41c3af56ec35874"); 
    dev1.withExternalId("0942dc67-35de-44f7-a061-743f59436a98"); 
    deviceList.add(dev1); 

    Device dev2 = new Device(); 
    dev2.withDateRegistered("2017-07-13T10:45:31.000+12:00"); 
    dev2.withAlias(""); 
    dev2.withId("bd2b027bbd0a2f17"); 
    dev2.withDescription("Samsung SM-A320Y"); 
    dev2.withTitle("bd2b027bbd0a2f17"); 
    dev2.withExternalId("0942dc67-35de-44f7-a061-743f59436a98"); 
    deviceList.add(dev2); 

    deviceResponse.setDevices(deviceList); 

    final RestTemplate restTemplate = new RestTemplate(); 
    GetDevicesResponse devices = restTemplate.getForObject("http://localhost:8091/devices/v1?externalId=0942dc67-35de-44f7-a061-743f59436a98", GetDevicesResponse.class); 

    assertThat(devices, sameBeanAs(deviceResponse)); 

} 

}

EDIT:

Je viens de découvrir que si je commente sur @Rule En partie, le test est passé - mais un fichier de pacte n'est pas généré. Shouod je spécifie explicitement un dossier "pacte" pour cela?

Répondre

1

J'ai eu un problème similaire avec les pactes n'étant pas générés après l'exécution du test. Je ne les ai jamais fait travailler en utilisant l'approche de l'annotation, mais je l'ai résolue en étendant ConsumerPactTestMk2. Pact configurera le mockserver et se moquera de la réponse pour vous.

public class PactForDevice extends ConsumerPactTestMk2 { 
    Map<String, String> headers = MapUtils.putAll(new HashMap<String, String>(), new String[]{"Content-Type", "application/json;charset=UTF-8"}); 

    public RequestResponsePact createPact(PactDslWithProvider builder) { 
     return builder 
      .given("Device M details") 
      .uponReceiving("retrieving Device details") 
      .path("/devices/v1") 
      .method("GET") 
      .query("externalId=0942dc67-35de-44f7-a061-743f59436a98") 
      .willRespondWith() 
      .headers(headers) 
      .status(200) 
      .body("{" + 
       "\"data\": [,\n " + 
       "{ \n" + 
       " \"dateRegistered\": \"2017-07-13T11:10:51.000+12:00\",\n" + 
       " \"alias\": \"\",\n" + 
       " \"id\": \"a02b14ee72192ab3\",\n" + 
       " \"description\": \"Samsung SM-G930F\",\n" + 
       " \"title\": \"a02b14ee72192ab3\",\n" + 
       " \"externalId\": \"0942dc67-35de-44f7-a061-743f59436a98\"\n" + 
       "},\n" + 
       "{\n" + 
       " \"dateRegistered\": \"2017-07-13T10:45:51.000+12:00\",\n" + 
       " \"alias\": \"\",\n" + 
       " \"id\": \"a41c3af56ec35874\",\n" + 
       " \"description\": \"Samsung SM-T819\",\n" + 
       " \"title\": \"a41c3af56ec35874\",\n" + 
       " \"externalId\": \"0942dc67-35de-44f7-a061-743f59436a98\"\n" + 
       " },\n" + 
       " {\n" + 
       " \"dateRegistered\": \"2017-07-13T10:45:31.000+12:00\",\n" + 
       " \"alias\": \"\",\n" + 
       " \"id\": \"bd2b027bbd0a2f17\",\n" + 
       " \"description\": \"Samsung SM-A320Y\",\n" + 
       " \"title\": \"bd2b027bbd0a2f17\",\n" + 
       " \"externalId\": \"0942dc67-35de-44f7-a061-743f59436a98\"\n" + 
       " }\n" + 
       "],\n" + 
       " \"message\": \"3 devices found for the user 0942dc67-35de-44f7-a061-743f59436a98\"\n" + 
       "}") 
     .toPact(); 
    } 

    @Override 
    protected String providerName() { 
     return "device-service-m"; 
    } 

    @Override 
    protected String consumerName() { 
     return "device-r"; 
    } 

    @Override 
    protected void runTest(MockServer mockServer) throws IOException { 
     final GetDevicesResponse deviceResponse = new GetDevicesResponse(); 

     final List<Device> deviceList = new ArrayList<>(); 
     Device dev = new Device(); 
     dev.withDateRegistered("2017-07-13T11:10:51.000+12:00"); 
     dev.withAlias(""); 
     dev.withId("a02b14ee72192ab3"); 
     dev.withDescription("Samsung SM-G930F"); 
     dev.withTitle("a02b14ee72192ab3"); 
     dev.withExternalId("0942dc67-35de-44f7-a061-743f59436a98"); 
     deviceList.add(dev); 

     Device dev1 = new Device(); 
     dev1.withDateRegistered("2017-07-13T10:45:51.000+12:00"); 
     dev1.withAlias(""); 
     dev1.withId("a41c3af56ec35874"); 
     dev1.withDescription("Samsung SM-T819"); 
     dev1.withTitle("a41c3af56ec35874"); 
     dev1.withExternalId("0942dc67-35de-44f7-a061-743f59436a98"); 
     deviceList.add(dev1); 

     Device dev2 = new Device(); 
     dev2.withDateRegistered("2017-07-13T10:45:31.000+12:00"); 
     dev2.withAlias(""); 
     dev2.withId("bd2b027bbd0a2f17"); 
     dev2.withDescription("Samsung SM-A320Y"); 
     dev2.withTitle("bd2b027bbd0a2f17"); 
     dev2.withExternalId("0942dc67-35de-44f7-a061-743f59436a98"); 
     deviceList.add(dev2); 

     deviceResponse.setDevices(deviceList); 

     String url = mockServer.getUrl(); 
     String path = "devices/v1"; 
     String query = "externalId=0942dc67-35de-44f7-a061-743f59436a98"; 

     URIBuilder uriBuilder = null; 
     try { 
      uriBuilder = new URIBuilder(url) 
           .setPath(path) 
           .setQuery(query); 
     } catch (URISyntaxException e) { 
      e.printStackTrace(); 
     } 

     GetDevicesResponse devices = new ObjectMapper().readValue(Request.Get(uriBuilder.toString()) 
       .addHeader("content-type", "application/json") 
       .execute().returnContent().asString(), GetDevicesResponse.class); 
     assertThat(devices, sameBeanAs(deviceResponse)); 
    } 
} 

Avec cette approche, je devais ajouter Google goyave 19 à mon pom. Mais ça fonctionne bien.

<dependency> 
    <groupId>com.google.guava</groupId> 
    <artifactId>guava</artifactId> 
    <version>19.0</version> 
</dependency> 
+0

Vous avez fait ma journée :) Cela a fonctionné comme un charme. Juste une chose, je n'avais pas besoin d'ajouter la dépendance à la goyave - elle générait un fichier pacte sans la dépendance. – ljs

+0

Est-il possible de spécifier plusieurs fournisseurs utilisant ceci? Merci .. – ljs

+0

Oui, vous pouvez créer un test différent pour chaque fournisseur que votre service consomme. Vous pouvez également ajouter plusieurs cas de test à la méthode createPact - si votre consommateur consomme plusieurs points de terminaison auprès d'un fournisseur. L'ajout de goyave 19 est également nécessaire si vous utilisez un nuage de printemps. – ertert

1

Il y a quelques problèmes avec votre test.

Problème # 1

Vous n'avez pas spécifié un port pour la règle de fournisseur de pacte, il commence le serveur simulé sur un port aléatoire. Votre test accède à votre fournisseur sur le port 8091, donc Pact échoue le test et signale qu'il n'a pas reçu la demande attendue, ce qui n'est pas le cas (la demande est passée à autre chose en écoute sur le port 8091).

Vous pouvez résoudre ce problème en fournissant le port 8091 à la règle (vous devrez arrêter tout ce qui s'exécute sur 8091), ou demandez à votre client d'utiliser le port du serveur fictif (d'appeler getMockServer().getPort()).

Problème # 2

Votre test utilise le modèle de repos ressort directement, ce qui signifie qu'il est pas vraiment tester quoi que ce soit autre que le client HTTP Spring et la désérialisation de haricots. Vous devriez utiliser le code client que vous avez (c'est-à-dire la classe qui utilise le modèle de repos) et l'appeler dans le test.

+0

Pour le problème n ° 2: Dans mon cas, le consommateur est en fait un projet à ressort avec la structure de service du contrôleur. Et dans les tests unitaires, ils utilisent un MockRestServiceServer pour invoquer la méthode particulière que cette URL va utiliser. 'mockServer = MockRestServiceServer.createServer (restTemplate);' puis 'mockServer.expect (requestTo (CoreMatchers.containsString (config.getDeviceResource()))) .etExpect (méthode (HttpMethod.GET);' C'est ce que vous avez dit Je devrais le faire, s'il te plait? – ljs

+0

Je n'ai pas beaucoup de contexte sur la structure de service de contrôleur de ressort, mais il semble que cette méthode serait la bonne chose à appeler. –