Wiremock возвращает неправильный тип контента для бегуна-заглушки Spring Cloud Contract - PullRequest
0 голосов
/ 31 мая 2018

Я пробую Spring-Cloud-Contract впервые.Я пытаюсь, чтобы мой клиент автоматически обнаружил заглушки контракта, но, хотя в моем контракте указан тип содержимого «application / json» в ответе, то, что я получаю из WireMock, имеет тип содержимого «application / octet»».Что я делаю не так?

В моем сервисе есть простой метод, который возвращает такую ​​модель из конечной точки /status:

{
  "name": string,
  "status": string
}

Мой контракт выглядит так:

import org.springframework.cloud.contract.spec.Contract

Contract.make {
    request {
        method('GET')
        headers {
            contentType(applicationJson())
        }
        url("/status")
    }

    response {
        status OK()
        body(
                name: "Demo",
                status: "RUNNING"
        )
        headers {
            contentType(applicationJson())
        }
    }
}

В моем клиенте у меня есть класс, который использует Spring RestTemplate для запроса этой конечной точки:

@Component
public class StatusClient {

    private final RestTemplate restTemplate;

    public StatusClient(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    public Status getStatus() {
        return this.restTemplate
                .exchange("http://localhost:8080/status", HttpMethod.GET, null, Status.class)
                .getBody();
    }
}

@Data
class Status implements Serializable {
    private String name;
    private String status;
}

Мой модульный тест использует @AutoConfigureStubRunner, чтобы получить последнюю версиюконтракт из локального репозитория и утверждение против ответа от контракта (например, name = Demo, status = RUNNING).

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureStubRunner(ids = {"com.example:contract-demo:+:8080"}, stubsMode = StubRunnerProperties.StubsMode.LOCAL)
public class StatusClientTests {

    @Autowired
    private StatusClient client;

    @Test
    public void testThatStatusReturnsSuccessfully() {
        Status result = this.client.getStatus();
        assertEquals("Demo", result.getName());
        assertEquals("RUNNING", result.getStatus());
    }
}

Когда я запускаю тест, WireMock сообщает о контракте, который он получил, как и ожидалось:

2018-05-31 11:36:49.919  INFO 14212 --- [tp1255723887-26] WireMock                                 : Request received:
127.0.0.1 - GET /status

User-Agent: [Java/1.8.0_161]
Connection: [keep-alive]
Host: [localhost:8080]
Accept: [application/json, application/*+json]



Matched response definition:
{
  "status" : 200,
  "body" : "{\"name\":\"Demo\",\"status\":\"RUNNING\"}",
  "headers" : {
    "contentType" : "application/json"
  },
  "transformers" : [ "response-template" ]
}

Response:
HTTP/1.1 200
contentType: [application/json]

Но когда RestTemplate пытается десериализовать его, он выдает исключение, потому что тип содержимого ответа на самом деле «application / octet», как только он попадает в методы для извлечения данных:

org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [class com.example.contractclientdemo.Status] and content type [application/octet-stream]

    at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:119)
    at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:991)
    at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:974)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:725)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:680)
    at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:600)
    at com.example.contractclientdemo.StatusClient.getStatus(StatusClient.java:18)

Я использую Finchley.RC2 для облачной версии Spring, и spring-cloud-starter-contract-stub-runner - моя единственная тестовая зависимость, кроме spring-boot-starter-test.

Я знаю, что WireMock возвращает неправильный тип контентапотому что я отладилглубоко в класс HttpMessageConverterExtractor в Spring, и это то, что метод getContentType возвращает при запросе.

Почему WireMock возвращает неправильный тип содержимого, хотя и сообщает правильный в журнале?И как я могу заставить его правильно вернуть application/json, чтобы я мог десериализовать мое простое сообщение?

Ответы [ 2 ]

0 голосов
/ 24 июля 2018

У меня была точно такая же проблема, как и у вас.Я решил это, добавив

headers {
  header 'Content-Type': 'application/json;charset=UTF-8'
}

к ответу.Похоже, в вашем ответе вы написали по-другому, но это помогло решить проблему в моем случае.Так что это как-то связано с этим.

Перед внесением изменений curl не показывал заголовок ответа Content-Type:

curl -v -H "Accept: application / json"localhost: 6565 / products / ABC
* Попытка 127.0.0.1 ...
* TCP_NODELAY set
* Подключение к локальному хосту (127.0.0.1) через порт 6565 (# 0)
GET / products / ABCHTTP / 1.1
Хост: localhost: 6565
Агент пользователя: curl / 7.58.0
Принимать: application / json

HTTP / 1.1 200 OK
Кодировка передачи: chunked
Сервер: Jetty (9.2.z-SNAPSHOT)

Соединение № 0 с локальным хостом оставлено без изменений

{  
  "price": {  
    "currencyCode": "EUR",  
    "value": "100.50"  
  },  
  "name": "Fake product"  
}

После внесения изменений curl вернул это и RestTemplateудалось десериализовать его.

HTTP / 1.1 200 OK
Тип содержимого: application / json; charset = UTF-8
Кодирование передачи: chunked
Сервер: Jetty (9.2.z-SNAPSHOT)

Вот мой рабочий контракт:

import org.springframework.cloud.contract.spec.Contract
Contract.make {
    description "should return product information"
    request{
        method GET()
        url("/products/ABC")
    }
    response {
        status 200
        headers {
            header 'Content-Type': 'application/json;charset=UTF-8'
    }
        body([
          name: 'Fake product',
          price:[
              currencyCode: 'EUR',
              value: 100.50
          ]
        ])
    }
}

Надеюсь, это поможет

0 голосов
/ 31 мая 2018

Я думаю, вы должны подать это как проблему в WireMock.Также вы не устанавливаете заголовок типа контента application / json в явном запросе.Может быть, это проблема?Также не должен ли это быть тип содержимого в качестве имени заголовка в заглушке ответа?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...