Spring Boot - Testing REST Clients With @RestClientTest - Example
In this section, we will learn how to test REST clients with @RestClientTest in Spring Boot application.
The Spring Framework provides the following Rest clients for making calls to REST endpoints:
- RestTemplate
- RestClient (Supporting from Spring 6.1 onwards)
- WebClient
- HTTP Interface
In this example we are using RestTemplate client for making call to REST endpoint. We will implement a service that will fetch data from the JSONPlaceholder API.
As the part of testing we are using MockRestServiceServer to mock real API. It eliminates the use of an actual server and thus speeds up the testing process.
1. @RestClientTest
Instead of bootstrapping the entire application context for every test, @RestClientTest initializes the Spring application context with only those beans needed to test REST Clients. It will auto-configure Jackson, GSON, Jsonb, configures a RestTemplateBuilder, and adds support for MockRestServiceServer.
The auto-configuration that @RestClientTest import by default are listed below:
- CacheAutoConfiguration
- GsonAutoConfiguration
- HttpMessageConvertersAutoConfiguration
- CodecsAutoConfiguration
- JacksonAutoConfiguration
- JsonbAutoConfiguration
- RestTemplateAutoConfiguration
- WebClientAutoConfiguration
- MockRestServiceServerAutoConfiguration
- WebClientRestTemplateAutoConfiguration
2. MockRestServiceServer
MockRestServiceServer provides mock responses from expected requests through the RestTemplate. It eliminates the use of an actual server and thus speeds up the testing process.
3. Creating a spring boot application
First, open the Spring initializr https://start.spring.io
Then, Provide the Group and Artifact name. We have provided Group name com.knf.dev.demo and Artifact restclienttest-example. Here I selected the Maven project - language Java 17 - Spring Boot 3.1.5, and Spring Web.
Then, click on the Generate button. When we click on the Generate button, it starts packing the project in a .zip(restclienttest-example) file and downloads the project. Then, Extract the Zip file.
Then, import the project on your favourite IDE.
Final Project Directory:
Complete pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.knf.dev.demo</groupId>
<artifactId>restclienttest-example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>restclienttest-example</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
</properties>
<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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<image>
<builder>paketobuildpacks/builder-jammy-base:latest</builder>
</image>
</configuration>
</plugin>
</plugins>
</build>
</project>
spring-boot-starter-test starter will provide following libraries:
- JUnit
- Spring Test & Spring Boot Test
- AssertJ
- Hamcrest
- Mockito
- JSONassert
- JsonPath
application.properties
todo.baseUrl = https://jsonplaceholder.typicode.com
Base URL of todo API(real) is declared inside application.properties.
Create Todo DTO
package com.knf.dev.demo.dto;
public class Todo {
public Integer userId;
public Integer id;
public String title;
public Boolean completed;
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Boolean getCompleted() {
return completed;
}
public void setCompleted(Boolean completed) {
this.completed = completed;
}
}
Create todo.json inside resource directory
We are using this JSON data for our testing purposes later.
{
"userId": 1,
"id": 1,
"title": "delectus aut autem",
"completed": false
}
Create Todo Service
package com.knf.dev.demo.service;
import com.knf.dev.demo.dto.Todo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class TodoService {
private final RestTemplate restTemplate;
public TodoService(RestTemplateBuilder restTemplateBuilder,
@Value("${todo.baseUrl}") String baseUrl) {
this.restTemplate = restTemplateBuilder.rootUri(baseUrl).build();
}
public Todo findById(Integer id) {
ResponseEntity<Todo> response
= restTemplate.getForEntity("/todos/{id}", Todo.class, id);
return response.getBody();
}
}
- RestTemplateBuilder is a Builder that can be used to configure and create a RestTemplate
- getForEntity() – retrieve a representation as ResponseEntity by doing a GET on the URL.
RestClientTestExampleApplication.java
package com.knf.dev.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class RestClientTestExampleApplication {
public static void main(String[] args) {
SpringApplication.run(RestClientTestExampleApplication.class, args);
}
}
Write Unit test for REST Client
Let’s write our test case by creating TodoServiceTest class,
Create TodoServiceTest class
package com.knf.dev.demo;
import com.knf.dev.demo.dto.Todo;
import com.knf.dev.demo.service.TodoService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.autoconfigure.web.client.RestClientTest;
import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.test.web.client.MockRestServiceServer;
import java.io.IOException;
import java.nio.charset.Charset;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
@RestClientTest(TodoService.class)
public class TodoServiceTest {
@Autowired
private MockRestServiceServer mockRestServiceServer;
@Autowired
private TodoService todoService;
@Value("classpath:todo.json")
private Resource resource;
@Test
void findById_ReturnsTheTodo() throws IOException {
final Integer id = 1;
mockRestServiceServer
.expect(requestTo("/todos/" + id))
.andRespond(withSuccess(resource.getContentAsString(Charset.defaultCharset()),
MediaType.APPLICATION_JSON));
Todo todo = todoService.findById(id);
assertEquals(1, todo.getUserId());
assertEquals(1, todo.getId());
assertEquals("delectus aut autem", todo.getTitle());
assertEquals(false, todo.getCompleted());
}
}
- MockRestServiceServer provides mock responses from expected requests through the RestTemplate. It eliminates the use of an actual server and thus speeds up the testing process.
- @RestClientTest will auto-configure Jackson, GSON, Jsonb, configures a RestTemplateBuilder, and adds support for MockRestServiceServer.
- Inject a Resource directly into a Spring bean with @Value.
- assertEquals() method asserts that two objects are equal. If they are not, an AssertionError without a message is thrown. If expected and actual are null, they are considered equal.
4. Run the test
Or you can run the test using following command:
mvn test -Dtest=TodoServiceTest