DEV Community

Shriharsh
Shriharsh

Posted on

6 1

Today I Learned: To use custom ClientHttpRequestFactory with MockRestServiceServer

Despite having some reservations about using Spring RestTemplate for writing JAX-RS client (see here), I chose to use Spring RestTemplate to implement a JAX RS client as I liked that I could write test cases by easily mocking the REST service I was consuming. Spring provides a very nice utility to mock REST service end-point: MockRestServiceServer. However, I ran into an pesky issue.

Problem

I developed my code along with the test cases using the above nice utility by Spring framework. Next step was to log all incoming and outgoing traffic. I was able to implement the feature by registering a custom LoggingInterceptor along with the BufferingClientHttpRequestFactory. The logging worked fine but my test cases started to fail. Although I ensured that I use BufferingClientHttpRequestFactory so that the response from the server can be read twice - once for logging and next by the application code, the test code would fail on the second read.

Diagnosis

I found that the MockRestServiceServer would override the BufferingClientHttpRequestFactory setup on the RestTemplate instance passed to it while creating the server.

@Override
public MockRestServiceServer build(RequestExpectationManager manager) {
    MockRestServiceServer server = new MockRestServiceServer(manager);
    MockClientHttpRequestFactory factory = server.new MockClientHttpRequestFactory();
    if (this.restTemplate != null) {
        this.restTemplate.setRequestFactory(factory);
    }
    if (this.asyncRestTemplate != null) {
        this.asyncRestTemplate.setAsyncRequestFactory(factory);
    }
    return server;
}

Enter fullscreen mode Exit fullscreen mode

Solution

On scouring further, I found that the there is a hack to work around this issue. Once the server is created, read the requestFactory instance created by the MockRestServiceServer using ReflectionTestUtils on RestTemplate instance and wrap it up with BufferingClientHttpRequestFactory.

@Before
public void setUp() throws Exception {
    mockServer = MockRestServiceServer.createServer(restTemplate);

    final ClientHttpRequestFactory requestFactory = 
        (ClientHttpRequestFactory) ReflectionTestUtils.getField(restTemplate, "requestFactory");

    restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(requestFactory));
}

Enter fullscreen mode Exit fullscreen mode

I hope this helps you as well.

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read more →

Top comments (2)

Collapse
 
ericathedev profile image
Erica Tanti

I use BufferingClientHttpRequestFactory so that the response from the server can be read twice - once for logging and next by the application code, the test code would fail on the second read.

This was happening to me when I removed BufferingClientHttpRequestFactory and I couldn't figure out what was happening. Thank you for explaining why!

Collapse
 
shriharshmishra profile image
Shriharsh

Welcome 😊

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

AWS GenAI Live!

GenAI LIVE! is a dynamic live-streamed show exploring how AWS and our partners are helping organizations unlock real value with generative AI.

Tune in to the full event

DEV is partnering to bring live events to the community. Join us or dismiss this billboard if you're not interested. ❤️