Testing the Spring RestTemplate With @RestClientTest

Last Updated:  August 27, 2021 | Published: March 14, 2020

While watching Andy Wilkinson's great talk, Testing Spring Boot Applications on YouTube, he brought my attention to a hidden gem for testing the Spring RestTemplate. In the past, I always wondered how to write proper tests for client classes using the RestTemplate to fetch data from external services. In his presentation, he mentioned the @RestClientTest annotation that provides everything you need to test such classes. Compared to WireMock for testing our RestTemplate in isolation, this solution requires less setup as everything is part of Spring Boot.

With this blog post, I'll walk you through a Spring Boot 2.4 application using the  @RestClientTest annotation.

Spring RestTemplate Project Setup

The application is a usual Tomcat-based Spring Boot Web MVC application. The RestTemplate is used to fetch data from a remote API.

Besides, we're using Java 16. This Java version is optional and not a must-have. However, we'll benefit from Java's new text block feature when preparing JSON strings:

That's everything we need. No additional dependency required as the @RestClientTest annotation is part of the spring-boot-test-autoconfigure dependency which comes with spring-boot-starter-test.

Please note that the upcoming test examples are using JUnit Jupiter (part of JUnit 5).  Nevertheless, I'll explain what needs to change when using JUnit 4.X.

Inside the @RestClientTest Annotation

Let's first have a look at the @RestClientTest  annotation to understand what's happening behind the scenes:

The annotation is used to combine (a lot of) other annotations mostly used for auto-configuration. Together all of these annotations only bootstrap the required beans to test a specific part of the application.

With @ExtendWith(SpringExtension.class) the annotation registers Spring's JUnit Jupiter extension. Among other things, we need this annotation to inject objects from the test's ApplicationContext. For those of you who are using JUnit 4, make sure to always add @RunWith(SpringRunner.class) to your tests. This is required as the SpringExtension only works with JUnit Jupiter.

Next @AutoConfigureWebClient is used to enable and configure the auto-configuration of web clients. By default, Spring Boot configures the RestTemplateBuilder for us. If we specify @AutoConfigureWebClient(registerRestTemplate=true) , also concrete RestTemplate beans are available to inject, which we'll see later on.

The last important annotation is @AutoConfigureMockRestServiceServer.  This ensures a bean of type MockRestServiceServer is part of the Spring TestContext and ready to inject into our test classes to mock the HTTP response.

Testing Code Using the RestTemplateBuilder

If we've already used the RestTemplate in the past, the following setup might look familiar:

Our UserClient basically returns a POJO from a remote API. For this demo, we're using a dummy API.

Testing this part of your application while mocking the RestTemplateBuilder results in a lot of setup ceremony. The benefit of just testing such code parts using only Mocktio is questionable. It would be great to include HTTP semantics and test different responses from the remote server.

We can do better than just mocking everything by using the@RestClientTest. Once we annotate a test class with this annotation, we have to specify which class we want to test,e.g.:@RestClientTest(UserClient.class).

Next, we can inject everything we need for our test

Given this MockRestSerivceServer instance, we can now specify the result of this mock server for each test case:

The example above is using the Java 16 text block feature to define the JSON string response. Besides the HTTP body, we can also configure the content type and HTTP status of the response.

For those of you, who don't use Java 16 yet, you can also use the injected ObjectMapper to create a valid JSON string:

We can now also test how our method behaves in case of a server error in the remote system:

The example above propagates the exception, but our client class might handle it differently and return null or an empty Optional, which we can easily verify with this setup.

Testing Code Using a Spring RestTemplate Bean

Furthermore, some parts of our application might not directly use the RestTemplateBuilder. It's also common to prepare different RestTemplate beans for our application inside a @Configuration class:

And the client directly injects the configured RestTemplate:

For such use cases, we have to set up our test class slightly different:

Finally, the MockRestSerivceServer provides a way to reset all expectations/recorded requests and verify that every expectation was actually used. This is quite helpful and can be integrated using the JUnit test lifecycle:

This ensures there are no side effects between tests.

Unfortunately, we can't use this whole setup if our application already uses the Spring WebClient instead of the RestTemplate. There is a different approach to have something similar for the WebClient, which is covered in another article.

Apart from the @RestClientTest annotation, Spring Boot offers further test slice annotations to verify different parts of our application in isolation:

The full source code (including all tests) for this Spring Boot application example is available on GitHub.

Have fun testing your Spring RestTemplate,

Phil

>