Я пробую 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
, чтобы я мог десериализовать мое простое сообщение?