2

I will answer my question myself, but I am not happy with my solution, so if there is a ready-made convenience class/method doing the same, let me know.

Problem statement

I am using Spring MockRestServiceServer in unit tests to mock a REST service call. I'd like to have quick access to the request body which comes to the mock REST server. Typically for logging or just for evaluating during the debugging.

The context for usage is as follows:

import org.springframework.test.web.client.MockRestServiceServer;

class MyTest {
    @Test
    void myTest() {
        MockRestServiceServer mockServer = ...;
        mockServer
            .expect(MockRestRequestMatchers.method(HttpMethod.POST))
            .andExpect(MockRestRequestMatchers.requestTo("http://mock.example.com/myservice"))

            // The following method does not exist, it's what I'd like to have
            .andCapture(body -> { 
                /* do something with the body */ 
                log.info(body);
            }) // the place for the Captor

            .andRespond(MockRestResponseCreators.withSuccess("The mock response", MediaType.TEXT_PLAIN))
        ;
    }
}

Question

Is there a ready-made class/method which would provide this "andCapture(body -> {})" functionality out of the box?

Honza Zidek
  • 9,204
  • 4
  • 72
  • 118

1 Answers1

5

The best solution I have so far is this:

.andExpect(request -> {
    final String body = ((ByteArrayOutputStream) request.getBody()).toString(StandardCharsets.UTF_8);
    /* do something with the body */
    log.info(body);
})

However, I'd expect that there might exist a convenience method for capturing directly the request body.

Honza Zidek
  • 9,204
  • 4
  • 72
  • 118
  • with a StringBuilder to catch the body, this can serve as the work around pattern of ArgumentCaptor! – gigi2 Oct 22 '21 at 21:26
  • @gigi2 Could you please elaborate your idea a little? – Honza Zidek Oct 25 '21 at 07:31
  • oh, I just mean to say a StringBuilder can be used out of the scope, then append the final string to the StringBuilder. thus it is accessible everywhere. Thank you for providing the solution. It works nicely for me – gigi2 Dec 09 '21 at 17:41
  • @gigi2 Oh, you mean using the `StringBuilder` as a wrapper for the `String` value to overcome the "outside-scope-variable-must-be-effectively-final limitation", in case you want to use the value *after* the `mockServer` processing chain? I usually use `AtomicReference` or `Optional` if a **really badly** need it, but it is generally considered as anti-pattern and not much recommended :) I have been recently involved a lot in reactive programming, when the lambda code is performed in a different thread much later, so I generally frown upon such solutions. Even if here it would work, – Honza Zidek Dec 10 '21 at 14:29