pact-jvm: как решить au.com.dius.pact.consumer.PactMismatchesException

Я пытаюсь создать договор между двумя нашими службами, используя pact-JVM. Но когда я пытаюсь запустить класс Java, я получаю это исключение.

1) Я подозреваю, что с телом Пакта что-то не так, это правильно? В теле JSON PactDslWithProvider есть дополнительный параметр 'message', но в методе runTest1() я приравниваю только списки, и когда я проверяю результаты, они для меня одинаковы. 2) Правильно ли указывать фактический URL-адрес поставщика в методе runTest1()? (поставщик уже на месте)

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)

Ниже мой класс 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));

}  

}

РЕДАКТИРОВАТЬ:

Я только что обнаружил, что если я закомментирую часть @Rule, тест будет пройден, но файл пакта не будет сгенерирован. Я должен явно указать папку "pact" для этого?

2 ответа

Решение

У меня была похожая проблема с пактами, не генерируемыми после запуска теста. Я никогда не заставлял их работать, используя подход аннотации, вместо этого я решил это, расширяя ConsumerPactTestMk2. Пакт установит mockserver и будет высмеивать ответ для вас.

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

При таком подходе мне пришлось добавить гугл гуаву 19 в мой пом. Но это работает хорошо.

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

Есть несколько проблем с вашим тестом.

Проблема № 1

Вы не указали порт для правила поставщика Pact, поэтому он запускает фиктивный сервер на случайном порту. Ваш тест обращается к вашему провайдеру через порт 8091, поэтому Pact не проходит тест и сообщает, что он не получил ожидаемый запрос, чего он не получил (запрос перешел к чему-то другому, прослушивающему порт 8091).

Вы можете исправить это, предоставив правилу порт 8091 (вам нужно отключить все, что работает на 8091), или заставить вашего клиента использовать порт сервера-макета (от вызова getMockServer().getPort()).

Проблема № 2

Ваш тест напрямую использует Spring Rest Template, что означает, что он на самом деле не тестирует ничего, кроме Spring-клиента Spring и десериализации компонента. Вы должны использовать любой клиентский код (т. Е. Класс, который использует шаблон rest) и вызывать его в тесте.

Другие вопросы по тегам