Spring Boot: Testing REST Clients with @RestClientTest

In Spring Boot, @RestClientTest is a specialized test annotation used for testing REST clients. It simplifies the setup of your test context and provides support for mocking and testing REST interactions with a RESTful web service. This tutorial will guide you through the process of setting up and using @RestClientTest in a Spring Boot application.

Prerequisites

  • JDK 17 or later
  • Maven or Gradle
  • IDE (IntelliJ IDEA, Eclipse, etc.)

Step 1: Set Up a Spring Boot Project

1.1 Create a New Spring Boot Project

Use Spring Initializr to create a new project with the following dependencies:

  • Spring Web
  • Spring Boot Test

Download and unzip the project, then open it in your IDE.

1.2 Configure application.properties

Set up the application properties for your project. This step is optional and only needed if you want to configure specific properties for your application.

# src/main/resources/application.properties

server.port=8080

Step 2: Create a REST Client

2.1 Create a Model Class

Create a model class that represents the data structure for your REST client.

package com.example.demo.model;

public class User {

    private Long id;
    private String name;
    private String email;

    // Getters and setters
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

2.2 Create a REST Client Service

Create a service class that uses RestTemplate to make REST calls.

package com.example.demo.service;

import com.example.demo.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class UserService {

    private final RestTemplate restTemplate;

    @Autowired
    public UserService(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    public User getUserById(Long id) {
        return restTemplate.getForObject("https://jsonplaceholder.typicode.com/users/" + id, User.class);
    }
}

Explanation:

  • UserService: A service class that uses RestTemplate to fetch user data from a REST API.
  • getUserById(Long id): A method that makes a GET request to fetch user data by ID.

Step 3: Create a Test for the REST Client

3.1 Add Test Dependencies

Ensure you have the necessary test dependencies in your pom.xml (for Maven) or build.gradle (for Gradle).

For Maven:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <scope>test</scope>
</dependency>

For Gradle:

testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.mockito:mockito-core'

3.2 Create a Test Class

Create a test class to test the UserService using @RestClientTest.

package com.example.demo.service;

import com.example.demo.model.User;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.client.RestClientTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import org.springframework.test.web.client.ExpectedCount;
import org.springframework.test.web.client.MockRestServiceServer;
import org.springframework.web.client.RestTemplate;

import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;

@RestClientTest(UserService.class)
@Import(UserService.class)
class UserServiceTest {

    @Autowired
    private UserService userService;

    @Autowired
    private MockRestServiceServer server;

    @MockBean
    private RestTemplate restTemplate;

    @Test
    void getUserById_shouldReturnUser() {
        // Arrange
        User mockUser = new User();
        mockUser.setId(1L);
        mockUser.setName("John Doe");
        mockUser.setEmail("john.doe@example.com");

        String url = "https://jsonplaceholder.typicode.com/users/1";

        Mockito.when(restTemplate.getForObject(url, User.class)).thenReturn(mockUser);

        // Act
        User user = userService.getUserById(1L);

        // Assert
        assertThat(user).isNotNull();
        assertThat(user.getId()).isEqualTo(1L);
        assertThat(user.getName()).isEqualTo("John Doe");
        assertThat(user.getEmail()).isEqualTo("john.doe@example.com");

        server.expect(ExpectedCount.once(), requestTo(url))
              .andRespond(withSuccess());
    }
}

Explanation:

  • @RestClientTest(UserService.class): Sets up a test context for the UserService class and configures the necessary beans for testing REST clients.
  • @MockBean: Creates a mock of the RestTemplate bean.
  • MockRestServiceServer: Allows setting up expectations on the requests that RestTemplate will make and providing mock responses.
  • Mockito.when(restTemplate.getForObject(url, User.class)).thenReturn(mockUser): Mocks the getForObject method of RestTemplate to return a mockUser object when the specified URL is called.
  • server.expect(ExpectedCount.once(), requestTo(url)).andRespond(withSuccess()): Sets an expectation that the specified URL will be called once and responds with a success status.

Step 4: Running the Tests

4.1 Run the Tests

You can run the tests using your IDE or from the command line using Maven or Gradle.

For Maven:

./mvnw test

For Gradle:

./gradlew test

4.2 Verify the Test Results

Ensure that all tests pass successfully. The test should verify that the UserService correctly interacts with the mocked REST API and returns the expected User object.

Conclusion

In this tutorial, you have learned how to use @RestClientTest to test REST clients in a Spring Boot application. This specialized test annotation simplifies the setup of your test context and provides support for mocking and testing REST interactions. By using MockRestServiceServer and Mockito, you can effectively test the behavior of your REST clients and ensure they work as expected.


Comments