In this tutorial, we will learn how to write a Unit test for Spring Boot POST REST API using JUnit and Mockito framework.
Learn Spring Boot Unit Testing CRUD REST API with JUnit and Mockito.
Spring boot provides spring-boot-starter-test dependency for unit testing and integration testing of the Spring boot application:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
The Spring Boot Starter Test dependency is a primary dependency for testing the Spring Boot Applications. It holds all the necessary elements required for the testing.
For the Unit testing Spring Boot REST APIs, we gonna use the following testing libraries:
- JUnit 5 Framework
- Mockito 4 (Latest)
- Hamcrest framework
- AssertJ Library
- JsonPath Library
JUnit 5 Framework
Mockito 4 (Latest)
Create Spring Boot Application
- Spring Web
- Spring Data JPA
- Lombok
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
Create JPA Entity
import lombok.*;
import javax.persistence.*;
@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Entity
@Table(name = "employees")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@Column(name = "first_name", nullable = false)
private String firstName;
@Column(name = "last_name", nullable = false)
private String lastName;
@Column(nullable = false)
private String email;
}
Create Repository Layer
import net.javaguides.springboot.model.Employee;
import org.springframework.data.jpa.repository.JpaRepository;
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
}
Create Service Layer
EmployeeService
import net.javaguides.springboot.model.Employee;
import java.util.List;
import java.util.Optional;
public interface EmployeeService {
Employee saveEmployee(Employee employee);
}
EmployeeServiceImpl
import net.javaguides.springboot.exception.ResourceNotFoundException;
import net.javaguides.springboot.model.Employee;
import net.javaguides.springboot.repository.EmployeeRepository;
import net.javaguides.springboot.service.EmployeeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class EmployeeServiceImpl implements EmployeeService {
private EmployeeRepository employeeRepository;
public EmployeeServiceImpl(EmployeeRepository employeeRepository) {
this.employeeRepository = employeeRepository;
}
@Override
public Employee saveEmployee(Employee employee) {
Optional<Employee> savedEmployee = employeeRepository.findByEmail(employee.getEmail());
if(savedEmployee.isPresent()){
throw new ResourceNotFoundException("Employee already exist with given email:" + employee.getEmail());
}
return employeeRepository.save(employee);
}
}
Controller Layer - POST REST API
Let's create Spring Boot POST REST API and in the next section, we will write a Unit test to test this REST API:import net.javaguides.springboot.model.Employee;
import net.javaguides.springboot.service.EmployeeService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/employees")
public class EmployeeController {
private EmployeeService employeeService;
public EmployeeController(EmployeeService employeeService) {
this.employeeService = employeeService;
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public Employee createEmployee(@RequestBody Employee employee){
return employeeService.saveEmployee(employee);
}
}
import net.javaguides.springboot.model.Employee;
import net.javaguides.springboot.service.EmployeeService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/employees")
public class EmployeeController {
private EmployeeService employeeService;
public EmployeeController(EmployeeService employeeService) {
this.employeeService = employeeService;
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public Employee createEmployee(@RequestBody Employee employee){
return employeeService.saveEmployee(employee);
}
}
Unit Test Spring Boot POST REST API
Now, let's create a Unit test for Spring boot POST REST API. We gonna use the @WebMvcTest annotation to load only EmployeeController class.import com.fasterxml.jackson.databind.ObjectMapper;
import net.javaguides.springboot.model.Employee;
import net.javaguides.springboot.service.EmployeeService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import static org.hamcrest.CoreMatchers.is;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.BDDMockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
@WebMvcTest
public class EmployeeControllerTests {
@Autowired
private MockMvc mockMvc;
@MockBean
private EmployeeService employeeService;
@Autowired
private ObjectMapper objectMapper;
@Test
public void givenEmployeeObject_whenCreateEmployee_thenReturnSavedEmployee() throws Exception{
// given - precondition or setup
Employee employee = Employee.builder()
.firstName("Ramesh")
.lastName("Fadatare")
.email("ramesh@gmail.com")
.build();
given(employeeService.saveEmployee(any(Employee.class)))
.willAnswer((invocation)-> invocation.getArgument(0));
// when - action or behaviour that we are going test
ResultActions response = mockMvc.perform(post("/api/employees")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(employee)));
// then - verify the result or output using assert statements
response.andDo(print()).
andExpect(status().isCreated())
.andExpect(jsonPath("$.firstName",
is(employee.getFirstName())))
.andExpect(jsonPath("$.lastName",
is(employee.getLastName())))
.andExpect(jsonPath("$.email",
is(employee.getEmail())));
}
}
We are using @MockBean annotation to add mock objects to the Spring application context. The mock will replace any existing bean of the same type in the application context.
The @MockBean annotation tells Spring to create a mock instance of EmployeeService and add it to the application context so that it's injected into EmployeeController. We have a handle on it in the test so that we can define its behavior before running each test.
Note that we are using MockMvc class to make REST API calls.
We are using ResultActions class to handle the response of the REST API.
We are using Mockito to stub the method calls.If you want to understand in detail then I highly suggest my Udemy course: Testing Spring Boot Application with JUnit and Mockito (Includes Testcontainers)
import com.fasterxml.jackson.databind.ObjectMapper;
import net.javaguides.springboot.model.Employee;
import net.javaguides.springboot.service.EmployeeService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import static org.hamcrest.CoreMatchers.is;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.BDDMockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
@WebMvcTest
public class EmployeeControllerTests {
@Autowired
private MockMvc mockMvc;
@MockBean
private EmployeeService employeeService;
@Autowired
private ObjectMapper objectMapper;
@Test
public void givenEmployeeObject_whenCreateEmployee_thenReturnSavedEmployee() throws Exception{
// given - precondition or setup
Employee employee = Employee.builder()
.firstName("Ramesh")
.lastName("Fadatare")
.email("ramesh@gmail.com")
.build();
given(employeeService.saveEmployee(any(Employee.class)))
.willAnswer((invocation)-> invocation.getArgument(0));
// when - action or behaviour that we are going test
ResultActions response = mockMvc.perform(post("/api/employees")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(employee)));
// then - verify the result or output using assert statements
response.andDo(print()).
andExpect(status().isCreated())
.andExpect(jsonPath("$.firstName",
is(employee.getFirstName())))
.andExpect(jsonPath("$.lastName",
is(employee.getLastName())))
.andExpect(jsonPath("$.email",
is(employee.getEmail())));
}
}
If you want to understand in detail then I highly suggest my Udemy course: Testing Spring Boot Application with JUnit and Mockito (Includes Testcontainers)
Output
Related Tutorials
- Spring Boot Unit Testing CRUD REST API with JUnit and Mockito
- Spring Boot Testing - Data Access Layer Integration Testing using Testcontainers
- Spring Boot Testing - REST API Integration Testing using Testcontainers
- Spring Data JPA Repository Testing using Spring Boot @DataJpaTest
- CRUD JUnit Tests for Spring Data JPA - Testing Repository Layer
- Spring Boot Integration Testing MySQL CRUD REST API Tutorial
Comments
Post a Comment
Leave Comment