Search code examples
javaspring-bootjunitresttemplate

Testing JSON mapping for a Spring Boot RestTemplate client


I have a REST API outside of my control (supplied by a different, distant team) which I need to consume from a Spring Boot application.

Currently I would like to write a test for that the request (not response) resulting from my RestTemplate invocation corresponds exactly to what is expected at the remote end. I have a sample JSON snippet that I would like to replicate from my code - given the same parameters as in the sample I should get an equivalent JSON snippet in the request body which I would then like to analyze to be certain.

My idea so far is to get RestTemplate to use a server under my control which then captures the JSON request. Apparently MockRestServiceServer is a good choice for this.

Is this the right approach? How do I configure MockRestServiceServer to allow me to do this?


Solution

  • If you're only interested in verifying the JSON mapping, you can always use Jackson's ObjectMapper directly and verify if the object structures match by using a library like JSONassert to verify if the serialized string matches your expected result. For example:

    @Autowired
    private ObjectMapper objectMapper;
    private Resource expectedResult = new ClassPathResource("expected.json");
    
    @Test
    public void jsonMatches() {
        Foo requestBody = new Foo();
        String json = objectMapper.writeValueAsString(requestBody);
        String expectedJson = Files
            .lines(expectedResult.getFile())
            .collect(Collectors.joining());
        JSONAssert.assertEquals(expectedJson, json, JSONCompareMode.LENIENT);
    }
    

    This test purely uses ObjectMapper to verify the JSON mapping and nothing else, so you could even do this without actually having to bootstrap Spring boot within your test (which could be faster). The downside of this is that if you're using a different framework than Jackson, or if RestTemplate changes its implementation, that this test could become obsolete.


    Alternatively, if you're interesting in verifying that the complete request matches (both URL, request method, request body and so on), you can use MockRestServiceServer as you mentioned. This can be done by adding the @SpringBootTest annotation to your test, autowiring RestTemplate and the service that invokes RestTemplate for example:

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class FooServiceTests {
        @Autowired
        private RestTemplate restTemplate;
        @Autowired
        private FooService fooService; // Your service
    
        private MockRestServiceServer server;
    
        @Before
        public void setUp() {
            server = MockRestServiceServer.bindTo(restTemplate).build();
        }
    }
    

    You can then set up your tests by using:

    @Test
    public void postUsesRestTemplate() throws IOException, URISyntaxException {
        Path resource = Paths.get(getClass().getClassLoader().getResource("expected-foo.json").toURI());
        String expectedJson = Files.lines(resource).collect(Collectors.joining());
        server.expect(once(), requestTo("http://example.org/api/foo"))
            .andExpect(method(HttpMethod.POST))
            .andExpect(MockRestRequestMatchers.content().json(expectedJson))
            .andRespond(withSuccess());
        // Invoke your service here
        fooService.post();
        server.verify();
    }