Spring Boot TestRestTemplate - Testing CRUD REST APIs

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my Udemy courses are real-time and project oriented courses.

▶️ Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️ For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh Fadatare on YouTube

This tutorial will guide you through using TestRestTemplate in Spring Boot for testing CRUD operations on a User entity. We will use an H2 in-memory database for data persistence and create the necessary service, repository, and controller layers.

What is TestRestTemplate?

TestRestTemplate is a template class provided by Spring Boot for integration testing that involves a running server. It is used to make RESTful calls to an actual server and is ideal for full-stack integration testing. 

Advantages of TestRestTemplate

Full-Stack Testing: TestRestTemplate is used for end-to-end testing of the application, including the web layer, server, and often the database.

Realistic Scenarios: It is closer to real-world scenarios where the application is running on an actual server, making it ideal for testing the complete stack.

Ease of Use: It offers a straightforward approach for making REST calls, simplifying the testing of RESTful APIs.

Ideal Use Cases for TestRestTemplate

  • Use TestRestTemplate, where you need to test the application as a whole using Integration testing.
  • Testing RESTful APIs in scenarios that closely mimic the production environment.
  • Situations where you want to test the application's interaction with external services or databases.

Testing Spring Boot CRUD REST APIs using TestRestTemplate 

In this tutorial, we'll create a Spring Boot application that performs CRUD operations on a User entity, using an H2 in-memory database for persistence. We'll then test these CRUD operations using TestRestTemplate. The application will be structured into three layers: Repository, Service, and Controller.

Project Setup 

Ensure you have the following dependencies in your pom.xml:
 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webf</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> 

The User Entity

import jakarta.persistence.*; @Entity public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String firstName; private String lastName; private String email; // Constructors, Getters, Setters } 

The UserRepository

import org.springframework.data.jpa.repository.JpaRepository; public interface UserRepository extends JpaRepository<User, Long> { } 

The UserService

import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; import java.util.Optional; @Service public class UserService { private final UserRepository userRepository; @Autowired public UserService(UserRepository userRepository) { this.userRepository = userRepository; } public User createUser(User user) { return userRepository.save(user); } public Optional<User> getUser(Long id) { return userRepository.findById(id); } public User updateUser(Long id, User userDetails) { User user = userRepository.findById(id).orElseThrow(); user.setFirstName(userDetails.getFirstName()); user.setLastName(userDetails.getLastName()); user.setEmail(userDetails.getEmail()); return userRepository.save(user); } public void deleteUser(Long id) { userRepository.deleteById(id); } public List<User> getAllUsers() { return userRepository.findAll(); } } 

The UserController

import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.List; @RestController @RequestMapping("/users") public class UserController { private final UserService userService; @Autowired public UserController(UserService userService) { this.userService = userService; } @PostMapping public ResponseEntity<User> createUser(@RequestBody User user) { return ResponseEntity.ok(userService.createUser(user)); } @GetMapping("/{id}") public ResponseEntity<User> getUser(@PathVariable Long id) { return userService.getUser(id) .map(ResponseEntity::ok) .orElse(ResponseEntity.notFound().build()); } @GetMapping public ResponseEntity<List<User>> getAllUsers() { return ResponseEntity.ok(userService.getAllUsers()); } @PutMapping("/{id}") public ResponseEntity<User> updateUser(@PathVariable Long id, @RequestBody User user) { return ResponseEntity.ok(userService.updateUser(id, user)); } @DeleteMapping("/{id}") public ResponseEntity<Void> deleteUser(@PathVariable Long id) { userService.deleteUser(id); return ResponseEntity.ok().build(); } } 

Writing Tests with TestRestTemplate

First, configure TestRestTemplate in your test class:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class UserControllerTest { @Autowired private TestRestTemplate testRestTemplate; // Test methods go here } 

Now, write tests for each CRUD operation. Create, retrieve, update, and delete User entities, and assert the responses using TestRestTemplate.

Create (POST)

Testing the creation of a new User.

@Test public void createUserTest() { User newUser = new User(null, "Alice", "Smith", "alice.smith@example.com"); ResponseEntity<User> response = testRestTemplate.postForEntity("/users", newUser, User.class); assertEquals(HttpStatus.OK, response.getStatusCode()); assertNotNull(response.getBody().getId()); assertEquals("Alice", response.getBody().getFirstName()); } 

Read (GET)

Testing retrieval of a User.

@Test public void getUserTest() { // Create a user to retrieve User newUser = new User(null, "Bob", "Jones", "bob.jones@example.com"); User createdUser = testRestTemplate.postForObject("/users", newUser, User.class); ResponseEntity<User> response = testRestTemplate.getForEntity("/users/" + createdUser.getId(), User.class); assertEquals(HttpStatus.OK, response.getStatusCode()); assertEquals("Bob", response.getBody().getFirstName()); } 

Update (PUT)

Testing the update of a User.

@Test public void updateUserTest() { // Create a user to update User newUser = new User(null, "Charlie", "Brown", "charlie.brown@example.com"); User createdUser = testRestTemplate.postForObject("/users", newUser, User.class); User updatedUser = new User(null, "Charles", "Brown", "charlie.brown@example.com"); testRestTemplate.put("/users/" + createdUser.getId(), updatedUser); ResponseEntity<User> response = testRestTemplate.getForEntity("/users/" + createdUser.getId(), User.class); assertEquals(HttpStatus.OK, response.getStatusCode()); assertEquals("Charles", response.getBody().getFirstName()); } 

Delete (DELETE)

Testing the deletion of a User.

@Test public void deleteUserTest() { // Create a user to delete User newUser = new User(null, "Dave", "Wilson", "dave.wilson@example.com"); User createdUser = testRestTemplate.postForObject("/users", newUser, User.class); testRestTemplate.delete("/users/" + createdUser.getId()); ResponseEntity<User> response = testRestTemplate.getForEntity("/users/" + createdUser.getId(), User.class); assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode()); } 

Conclusion

In this tutorial, we've demonstrated how to use TestRestTemplate for testing CRUD operations on a User entity in a Spring Boot application, backed by an H2 in-memory database. This approach is ideal for full-stack integration testing, providing a realistic testing environment while ensuring the correct behavior of the RESTful service.

Comments

Spring Boot 3 Paid Course Published for Free
on my Java Guides YouTube Channel

Subscribe to my YouTube Channel (165K+ subscribers):
Java Guides Channel

Top 10 My Udemy Courses with Huge Discount:
Udemy Courses - Ramesh Fadatare