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 endpointWe 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

When using JUnit 4, this annotation should be used in combination with @RunWith(SpringRunner.class). But for this example  we are using JUnit 5, there’s no need to add the equivalent @ExtendWith(SpringExtension.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

Popular posts from this blog

Learn Java 8 streams with an example - print odd/even numbers from Array and List

Java Stream API - How to convert List of objects to another List of objects using Java streams?

Registration and Login with Spring Boot + Spring Security + Thymeleaf

Java, Spring Boot Mini Project - Library Management System - Download

ReactJS, Spring Boot JWT Authentication Example

Top 5 Java ORM tools - 2024

Java - Blowfish Encryption and decryption Example

Spring boot video streaming example-HTML5

Google Cloud Storage + Spring Boot - File Upload, Download, and Delete