pact-foundation / pact-jvm

JVM version of Pact. Enables consumer driven contract testing, providing a mock service and DSL for the consumer project, and interaction playback and verification for the service provider project.
https://docs.pact.io
Apache License 2.0
1.08k stars 479 forks source link

Mock Server not deserializing JSON post body #785

Open DeuceTheCoder opened 5 years ago

DeuceTheCoder commented 5 years ago

I'm writing a test for a post request, and I'm trying to create matchers for the post request body. My code is below:

    @Override
    protected RequestResponsePact createPact(PactDslWithProvider builder) {
        return builder.uponReceiving("Test Pact")
                .path("/test")
                .method("POST")
                .headers("Content-Type", "application/json")
                .body(getPostBody())
                .willRespondWith()
                .status(201)
                .body(getCreateResponse())
                .toPact();
    }

    private DslPart getPostBody() {
        return newJsonBody(body -> {
            body.stringValue("foo", "bar");
        }).build();
    }

....

    @Override
    protected void runTest(MockServer mockServer) throws IOException {
        MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
        messageConverter.setObjectMapper(objectMapper);
        RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder()
                .rootUri(mockServer.getUrl())
                .additionalMessageConverters(messageConverter);
        RestTemplate restTemplate = restTemplateBuilder.build();

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        String requestBody = "{\"foo\": \"bar\"}";

        ResponseEntity<JsonNode> response = restTemplate.postForEntity(
                "/test",
                new HttpEntity<>(requestBody, headers),
                JsonNode.class);
    }

Upon running this test, I receive the following error:

java.lang.AssertionError: Pact Test function failed with an exception, possibly due to Mismatches(mismatches=[PartialMismatch(mismatches=[BodyMismatch(expected=Map(foo -> bar), actual={"foo": "bar"}, mismatch=Type mismatch: Expected Map Map(foo -> bar) but received String '{"foo": "bar"}', path=$, diff=-{
-    "foo": "bar"
-}
+"{\"foo\": \"bar\"}")])])

How do I make the mock server convert the JSON string in the request to a map in order to correctly match?

uglyog commented 5 years ago

I can't see anything wrong with your test. Check the logs, it should show you what was actually received (you may need to enable DEBUG level logs).

My assumption is the content type is not being sent correctly. The only difference I can see from a SO search is forcing the generic type HttpEntity<String> entity = new HttpEntity<>(json, headers); but I don't see how that could make it behave incorrectly.

DeuceTheCoder commented 5 years ago

I gave that a try, and it still fails (no big surprise there). I've fallen back to using a Jackson ObjectMapper to write the string into a JsonNode object, and posting the result.