1

I replaced RestTemplate with RestClient and I had some integration tests with the help of MockRestServiceServer from Spring.

MockRestServiceServer is not compatible with RestClient.

The solution is to use @RestClientTest, but this is a sliced test and I don't want this or use OKhttpServer which is what Spring is using now (https://github.com/spring-projects/spring-framework/blob/main/spring-web/src/test/java/org/springframework/web/client/RestClientIntegrationTests.java) but I don't want to add an external dependency outside Spring

I would like to know if the Spring team is planning on releasing an equivalent to MockRestServiceServer that works with RestClient.

Thank you.

2 Answers 2

0

you can see in documentation

static MockRestServiceServer.MockRestServiceServerBuilder
bindTo(RestClient.Builder restClientBuilder)

Return a builder for a MockRestServiceServer that should be used to reply to the RestClient for the given RestClient.Builder.

so based on doc the following should work

@Test
void testRestClientCall() {
    RestClient.Builder builder = RestClient.builder();
    MockRestServiceServer mockServer = MockRestServiceServer.bindTo(builder).build();
    RestClient client = builder.build();

    mockServer.expect(requestTo("/api/data"))
              .andRespond(withSuccess("{\"key\":\"value\"}", MediaType.APPLICATION_JSON));

    String response = client.get()
                            .uri("/api/data")
                            .retrieve()
                            .body(String.class);

    assertEquals("{\"key\":\"value\"}", response);
    mockServer.verify();
}

source: doc

Sign up to request clarification or add additional context in comments.

2 Comments

Hello Mohammed, Thanks for the answer, the problem is that i am doing a full integration test so i am using mockMvc.perform(MockMvcRequestBuilders.post(METRICS_BASE_URL + "/query/range") .contentType(MediaType.APPLICATION_JSON).content(requestPayload)); And the request insists in trying to go to the real server instead of being intercepted, Thanks in advance
please can you update the question and provide me with a test code so I can review and help you out :), I encourage you to share code or copy paste the code and change only var name this way you don't expose the logic, understanding the test and reading your code will help me reproduce and fix it :)
0

RestClient does work with MockRestServiceServer.

Consider the following component:

@Component
public class MyClient {

    private final RestClient restClient;

    // it's important to inject the RestClient.Builder, as it will be configured
    // by the @RestClientTest to interact with the MockRestServiceServer
    public MyClient(RestClient.Builder builder) {
        this.restClient = builder.build();
    }

    public String doSomething() {
        // do whatever you want to do as a client
        return restClient.get().uri("/path/resource").retrieve().body(String.class);
    }

}

Then your integration test can look as easy as this:

@RestClientTest(MyClient.class)
class MyClientIT {

    @Autowired
    private MockRestServiceServer server;

    @Autowired
    private MyClient myClient;

    @Test
    void testSomething() {
        server.expect(requestTo("/path/resource")).andRespond(withSuccess("success", MediaType.TEXT_PLAIN));
        var result = myClient.doSomething();
        assertThat(result).isEqualTo("success");
        server.verify(); // verify the server received the expected request
    }

}

If you want to customize the RestClient (e.g. for reuse), make sure to build it using an injected RestClient.Builder. For example, if you have a configuration like that:

@Configuration
public class MyClientConfiguration {

    // it's important to use the injected RestClient.Builder, not build a new one!
    @Bean
    public RestClient customizedRestClient(RestClient.Builder builder) {
        // customize it, for example
        return builder.baseUrl("https://remote-server.com/").build();
    }

}

Then ensure to use the RestClient in your component:

@Component
public class MyClient {

    private final RestClient restClient;

    public MyClient(RestClient customizedRestClient) {
        this.restClient = customizedRestClient;
    }

    public String doSomething() {
        // do whatever you want to do as a client
        return restClient.get().uri("/path/resource").retrieve().body(String.class);
    }

}

Last, you need to import the configuration in your integration test so that MyClient can be autowired. Please note that the RestClient.Builder is provided by the RestClientTest when building the customizedRestClient bean. Also, the test needs to adapt to the base url.

@RestClientTest({ MyClient.class, MyClientConfiguration.class })
class MyClientIT {

    @Autowired
    private MockRestServiceServer server;

    @Autowired
    private MyClient myClient;

    @Test
    void testSomething() {
        server.expect(requestTo("https://remote-server.com/path/resource"))
                .andRespond(withSuccess("success", MediaType.TEXT_PLAIN));
        var result = myClient.doSomething();
        assertThat(result).isEqualTo("success");
        server.verify(); // verify the server received the expected request
    }

}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.