JUnit and Mockito in Spring Boot
As we all know, when it comes to development Unit testing is one of the major important practices to be maintained in application development.
In this article let us have a look at Junit and Mockito frameworks of Unit testing in Java applications for Rest apis.
The topic includes:
- What is UnitTesting?
- What is JUnit?
- What is the Mockito Framework?
- What is Mocking?
- Step By Step Implementation
What is UnitTesting?
Unit Testing is known as one of the continuous processes of Agile methodology. Unit testing comes into the picture at the developer’s level. Unit testing is a type of software testing in which individual components of the software application are tested.
Consider you are writing a Rest API, so for each of the APIs, we can write the test cases and test in the application before committing to our main API. In unit testing, we will mock the services, which means we will not call the database every time instead we will use the mockup data.
What is JUnit?
JUnit is a unit testing framework for Java programming language. It plays a major role in test-driven development and is known as a family of Unit testing frameworks known as xUnit.
JUnit provides the developer with an idea of first testing and then coding so that we will be sure of what type of data is required before implementing the actual APIs.
Using JUnit increases the productivity of the programmer and maintains application stability.
Since JUnit is a framework for writing test cases, it provides annotations to identify the test methods and provides assertions for testing the expected results.
What is the Mockito Framework?
Mockito is a Java-based mocking framework used for unit testing of Java applications. Mockito was released as an open-source testing framework under the MIT License.
Mockito internally uses the Java reflection API to generate the mock objects. The main purpose of using the Mockito framework is to simplify development by mocking the external dependencies and using them in the test code. We can also use Mockito with other testing frameworks like JUnit and TestNG.
What is Mocking?
Mocking is the process of developing the objects that act as the mock or clone of objects. That is instead of using the real objects we will be using the mocked objects. Mock objects provide specific or dummy inputs and outputs.
Step By Step Implementation
Step 1: Create a Spring Boot application using Spring initialize and add the following dependencies.
- Spring Web
- Spring Data JPA
- Lombok
Generate the Spring boot project as a zip file, extract it, and import it into the IDE
Step 2: Make sure that you have added the below dependencies in your spring boot project:
<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>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
Step 3: Create a JPA Entity
Now create an Employee JPA entity with the following content:
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;
}
Note that we are using Lombok annotations to reduce the boilerplate code.
Step 4: Create Repository Layer
Now create EmployeeRepository which extends the JpaRepository interface:
import net.jUnitApplication.springboot.model.Employee;
import org.springframework.data.jpa.repository.JpaRepository;
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
}
Step 5: Create Service Layer
Create an EmployeeService interface with CRUD methods:
import net.jUnitApplication.springboot.model.Employee;
import java.util.List;
import java.util.Optional;
public interface EmployeeService {
Employee saveEmployee(Employee employee);
List<Employee> getAllEmployees();
Optional<Employee> getEmployeeById(long id);
Employee updateEmployee(Employee updatedEmployee);
void deleteEmployee(long id);
}
Now create an EmployeeServiceImpl class that implements the EmployeeService interface:
import net.jUnitApplication.springboot.exception.ResourceNotFoundException;
import net.jUnitApplication.springboot.model.Employee;
import net.jUnitApplication.springboot.repository.EmployeeRepository;
import net.jUnitApplication.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);
}
@Override
public List<Employee> getAllEmployees() {
return employeeRepository.findAll();
}
@Override
public Optional<Employee> getEmployeeById(long id) {
return employeeRepository.findById(id);
}
@Override
public Employee updateEmployee(Employee updatedEmployee) {
return employeeRepository.save(updatedEmployee);
}
@Override
public void deleteEmployee(long id) {
employeeRepository.deleteById(id);
}
}
Step 6: Unit Testing Service Layer using JUnit 5 and Mockito
Let us write the Unit test case for EmployeeService. We should be able to write unit tests for EmployeeService WITHOUT using any Spring features.
We will be creating a mock of EmployeeRepository using @Mock and create an EmployeeServiceImpl instance using the mock EmployeeRepository instance.
import net.jUnitApplication.springboot.exception.ResourceNotFoundException;
import net.jUnitApplication.springboot.model.Employee;
import net.jUnitApplication.springboot.repository.EmployeeRepository;
import net.jUnitApplication.springboot.service.impl.EmployeeServiceImpl;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.willDoNothing;
import static org.mockito.Mockito.*;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
@ExtendWith(MockitoExtension.class)
public class EmployeeServiceTests {
@Mock
private EmployeeRepository employeeRepository;
@InjectMocks
private EmployeeServiceImpl employeeService;
private Employee employee;
@BeforeEach
public void setup(){
//employeeRepository = Mockito.mock(EmployeeRepository.class);
//employeeService = new EmployeeServiceImpl(employeeRepository);
employee = Employee.builder()
.id(1L)
.firstName("Ramesh")
.lastName("Fadatare")
.email("ramesh@gmail.com")
.build();
}
// JUnit test for saveEmployee method
@DisplayName("JUnit test for saveEmployee method")
@Test
public void givenEmployeeObject_whenSaveEmployee_thenReturnEmployeeObject(){
// given - precondition or setup
when(employeeRepository.findByEmail(employee.getEmail()))
.thenReturn(Optional.empty());
when(employeeRepository.save(employee)).thenReturn(employee);
System.out.println(employeeRepository);
System.out.println(employeeService);
// when - action or the behaviour that we are going test
Employee savedEmployee = employeeService.saveEmployee(employee);
System.out.println(savedEmployee);
// then - verify the output
assertThat(savedEmployee).isNotNull();
}
}
JUnit test for getAllEmployees method
@DisplayName("JUnit test for getAllEmployees method")
@Test
public void givenEmployeesList_whenGetAllEmployees_thenReturnEmployeesList(){
// given - precondition or setup
Employee employee1 = Employee.builder()
.id(2L)
.firstName("Tony")
.lastName("Stark")
.email("tony@gmail.com")
.build();
when(employeeRepository.findAll()).thenReturn(List.of(employee,employee1));
// when - action or the behaviour that we are going test
List<Employee> employeeList = employeeService.getAllEmployees();
// then - verify the output
assertThat(employeeList).isNotNull();
assertThat(employeeList.size()).isEqualTo(2);
}
JUnit test for getEmployeeById method
@DisplayName("JUnit test for getEmployeeById method")
@Test
public void givenEmployeeId_whenGetEmployeeById_thenReturnEmployeeObject(){
// given
when(employeeRepository.findById(1L)).thenReturn(Optional.of(employee));
// when
Employee savedEmployee = employeeService.getEmployeeById(employee.getId()).get();
// then
assertThat(savedEmployee).isNotNull();
}
JUnit test for updateEmployee method
@DisplayName("JUnit test for updateEmployee method")
@Test
public void givenEmployeeObject_whenUpdateEmployee_thenReturnUpdatedEmployee(){
// given - precondition or setup
when(employeeRepository.save(employee)).thenReturn(employee);
employee.setEmail("ram@gmail.com");
employee.setFirstName("Ram");
// when - action or the behaviour that we are going test
Employee updatedEmployee = employeeService.updateEmployee(employee);
// then - verify the output
assertThat(updatedEmployee.getEmail()).isEqualTo("ram@gmail.com");
assertThat(updatedEmployee.getFirstName()).isEqualTo("Ram");
}
JUnit test for deleteEmployee method
@DisplayName("JUnit test for deleteEmployee method")
@Test
public void givenEmployeeId_whenDeleteEmployee_thenNothing(){
// given - precondition or setup
long employeeId = 1L;
doNothing().when(employeeRepository).deleteById(employeeId);
// when - action or the behaviour that we are going test
employeeService.deleteEmployee(employeeId);
// then - verify the output
verify(employeeRepository, times(1)).deleteById(employeeId);
}
The above example code gives the CRUD operation testing of REST APIs using Junit and Mockito.
I hope this article is helpful. Thank you for reading. Please clap, share and comment. it will encourage me to write more such articles. Do share your valuable suggestions, I appreciate your honest feedback!!!