The Master Class of "Learn Spring Security" is out:
1. Introduction
This article is a quick introduction to a new feature of the upcoming Spring Boot 1.4.0 release — the @RestClientTest annotation.
The new annotation helps simplify and speed up the testing of REST clients in your Spring applications.
And of course it’s already available as a part of the first release candidate Spring Boot 1.4.0.
2. REST Client Support in Spring Boot Pre-1.4
Spring Boot is a handy framework that provides many auto-configured Spring beans with typical settings that allow you to concentrate less on configuration of a Spring application and more on your code and business logic.
But in version 1.3 we don’t get a lot of help when we want to create or test REST services clients. Its support for REST clients is not very deep.
To create a client for a REST API – a RestTemplate instance is typically used. Usually it has to be configured before usage and its configuration may vary, so Spring Boot does not provide any universally configured RestTemplate bean.
Same goes for testing REST clients. Before Spring Boot 1.4.0, the procedure of testing a Spring REST client was not very different than in any other Spring-based application. You would create a MockRestServiceServer instance, bind it to RestTemplate instance under test and provide it with mock responses to requests, like this:
RestTemplate restTemplate = new RestTemplate(); MockRestServiceServer mockServer = MockRestServiceServer.bindTo(restTemplate).build(); mockServer.expect(requestTo("/greeting")) .andRespond(withSuccess()); // Test code that uses the above RestTemplate ... mockServer.verify();
You would also have to initialize the Spring container and make sure that only the needed components are loaded into the context, to speed up the context load time (and consequently, the test execution time).
3. New REST Client Features in Spring Boot 1.4
In Spring Boot 1.4, the team has made a solid effort to simplify and speed up the creation and testing of REST clients.
So, let’s check out the new features.
3.1. Adding Spring Boot 1.4.0 to Your Project
First, you’ll need to make sure your project is using Spring Boot 1.4.x:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.4.0.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent>
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
And if you read this article prior to 1.4.0 release, you should also make sure to include Spring snapshot and milestone repositories, as described in the article “Spring Maven Repositories”, and use Spring Boot version 1.4.0.RC1. Newest release versions can be found here.
3.2. RestTemplateBuilder
Spring Boot 1.4 brings both the auto-configured RestTemplateBuilder to simplify creating RestTemplates, and the matching @RestClientTest annotation to test the clients built with RestTemplateBuilder. Here’s how you can create a simple REST client with RestTemplateBuilder auto-injected for you:
@Service public class DetailsServiceClient { private final RestTemplate restTemplate; public DetailsServiceClient(RestTemplateBuilder restTemplateBuilder) { restTemplate = restTemplateBuilder.build(); } public Details getUserDetails(String name) { return restTemplate.getForObject("/{name}/details", Details.class, name); } }
Notice that we did not explicitly wire the RestTemplateBuilder instance to a constructor. This is possible thanks to a new Spring 4.3 feature called implicit constructor injection, which is discussed in this article.
RestTemplateBuilder provides convenience methods for registering message converters, error handlers, URI template handlers, basic authorization and also use any additional customizers that you need.
3.3. @RestClientTest
For testing such a REST client built with RestTemplateBuilder, you may use a SpringRunner-executed test class annotated with @RestClientTest. This annotation disables full auto-configuration and only applies configuration relevant to REST client tests, i.e. Jackson or GSON auto-configuration and @JsonComponent beans, but not regular @Component beans.
@RestClientTest ensures that Jackson and GSON support is auto-configured, and also adds pre-configured RestTemplateBuilder and MockRestServiceServer instances to the context. The bean under test is specified with value or components attribute of the @RestClientTest annotation:
@RunWith(SpringRunner.class) @RestClientTest(DetailsServiceClient.class) public class DetailsServiceClientTest { @Autowired private DetailsServiceClient client; @Autowired private MockRestServiceServer server; @Autowired private ObjectMapper objectMapper; @Before public void setUp() throws Exception { String detailsString = objectMapper.writeValueAsString(new Details("John Smith", "john")); this.server.expect(requestTo("/john/details")) .andRespond(withSuccess(detailsString, MediaType.APPLICATION_JSON)); } @Test public void whenCallingGetUserDetails_thenClientMakesCorrectCall() throws Exception { Details details = this.client.getUserDetails("john"); assertThat(details.getLogin()).isEqualTo("john"); assertThat(details.getName()).isEqualTo("John Smith"); } }
Firstly, we need to ensure that this test is run with SpringRunner by adding the @RunWith(SpringRunner.class) annotation.
So, what’s new?
First – the @RestClientTest annotation allows us to specify the exact service under test – in our case it is the DetailsServiceClient class. This service will be loaded into the test context, while everything else is filtered out.
This allows us to autowire the DetailsServiceClient instance inside our test and leave everything else outside, which speeds up the loading of the context.
Second – as the MockRestServiceServer instance is also configured for a @RestClientTest-annotated test (and bound to the DetailsServiceClient instance for us), we can simply inject it and use.
Finally – JSON support for @RestClientTest allows us to inject the Jackson’s ObjectMapper instance to prepare the MockRestServiceServer’s mock answer value.
All that is left to do is to execute the call to our service and verify the results.
4. Conclusion
In this article we’ve discussed the new @RestClientTest annotation that allows easy and quick testing of REST clients built with Spring and is expected in the upcoming Spring Boot 1.4.0 release.
The source code for the article is available on GitHub.