In this comprehensive guide, we'll explore how to test REST clients in Spring Boot using @RestClientTest
. This annotation simplifies testing REST clients by auto-configuring only the necessary components, making tests faster and more focused.
Table of Contents
- Introduction to @RestClientTest
- Setting Up a REST Client
- Writing Tests with @RestClientTest
- Mocking REST API Responses with MockRestServiceServer
- Advanced Testing Scenarios
- Best Practices
- Conclusion
1. Introduction to @RestClientTest
@RestClientTest
is a Spring Boot test annotation that focuses only on testing REST clients. It:
- Auto-configures Jackson/GSON support.
- Provides a
MockRestServiceServer
to mock HTTP responses. - Excludes full auto-configuration, making tests faster.
When to Use @RestClientTest?
- When testing a
RestTemplate
orWebClient
-based REST client. - When you need to mock external API responses.
- When you want lightweight tests without loading the entire Spring context.
2. Setting Up a REST Client
Let’s create a simple REST client that fetches user data from an external API.
Step 1: Define a User Model
public record User(Long id, String name, String email) {}
Step 2: Create a REST Client Service
@Service
public class UserService {
private final RestTemplate restTemplate;
public UserService(RestTemplateBuilder restTemplateBuilder) {
this.restTemplate = restTemplateBuilder.build();
}
public User getUserById(Long id) {
String url = "https://api.example.com/users/{id}";
return restTemplate.getForObject(url, User.class, id);
}
}
Step 3: Configure RestTemplate
(Optional)
If you need custom configurations (e.g., timeouts, interceptors), define a RestTemplate
bean:
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder
.setConnectTimeout(Duration.ofSeconds(5))
.setReadTimeout(Duration.ofSeconds(5))
.build();
}
}
3. Writing Tests with @RestClientTest
Now, let’s test UserService
using @RestClientTest
.
Basic Test Structure
@RestClientTest(UserService.class) // Focuses only on UserService and RestTemplate
@AutoConfigureWebClient(registerRestTemplate = true)
class UserServiceTest {
@Autowired
private MockRestServiceServer mockServer; // Mock server for REST calls
@Autowired
private UserService userService; // The service under test
@Test
void getUserById_ReturnsUser_WhenUserExists() throws Exception {
// Mock API response
mockServer.expect(requestTo("https://api.example.com/users/1"))
.andRespond(withSuccess(
"""
{
"id": 1,
"name": "John Doe",
"email": "john@example.com"
}
""",
MediaType.APPLICATION_JSON
));
// Call the service
User user = userService.getUserById(1L);
// Verify
assertThat(user.id()).isEqualTo(1L);
assertThat(user.name()).isEqualTo("John Doe");
mockServer.verify(); // Ensure expected requests were made
}
}
Explanation
@RestClientTest(UserService.class)
→ Configures onlyUserService
andRestTemplate
.MockRestServiceServer
→ Mocks the external API.expect(requestTo(...))
→ Defines expected request.andRespond(withSuccess(...))
→ Defines mock response.mockServer.verify()
→ Ensures the expected request was made.
4. Mocking REST API Responses with MockRestServiceServer
MockRestServiceServer
allows mocking different responses:
Mocking Success Response
mockServer.expect(requestTo("/users/1"))
.andRespond(withSuccess(
"""
{
"id": 1,
"name": "John Doe"
}
""",
MediaType.APPLICATION_JSON
));
Mocking Error Response (404)
mockServer.expect(requestTo("/users/999"))
.andRespond(withStatus(HttpStatus.NOT_FOUND));
Mocking Error Response (500)
mockServer.expect(requestTo("/users/1"))
.andRespond(withServerError());
Matching Request Body (POST/PUT)
mockServer.expect(requestTo("/users"))
.andExpect(method(HttpMethod.POST))
.andExpect(content().json("""
{
"name": "Jane Doe"
}
"""))
.andRespond(withSuccess());
5. Advanced Testing Scenarios
Testing with Custom Headers
mockServer.expect(requestTo("/users/1"))
.andExpect(header("Authorization", "Bearer token123"))
.andRespond(withSuccess(...));
Testing Timeout Scenarios
@Test
void getUserById_ThrowsTimeoutException_WhenServerSlow() {
mockServer.expect(requestTo("/users/1"))
.andRespond(withTimeout());
assertThrows(ResourceAccessException.class, () -> {
userService.getUserById(1L);
});
}
Using JSON Path Assertions
mockServer.expect(requestTo("/users"))
.andExpect(jsonPath("$.name", is("John Doe")))
.andRespond(withSuccess(...));
6. Best Practices
- Keep Tests Focused
- Test only REST client logic, not business logic.
- Use
MockRestServiceServer
- Avoid real HTTP calls in tests.
- Verify Requests
- Always call
mockServer.verify()
to ensure expected requests were made.
- Always call
- Test Error Cases
- Mock 4xx/5xx responses to ensure error handling works.
- Use
@RestClientTest
for REST Clients Only- For full integration tests, use
@SpringBootTest
.
- For full integration tests, use
7. Conclusion
@RestClientTest
is a powerful tool for testing REST clients in Spring Boot. It:
- Provides a lightweight test environment.
- Uses
MockRestServiceServer
to mock HTTP responses. - Makes testing REST clients fast and reliable.
By following this guide, you can write efficient and maintainable tests for your REST clients.