Java Spring Mock Repository Tutorial
In this article, we are going to explain in detail how to mock a repository in Spring Boot.
First, we will build a basic Spring Boot application. Then, we will illustrate how to use Mockito to unit test the service layer.
Generate Spring Boot Project
Before diving deep into the details, let’s create a simple Spring Boot application.
To do so, we will use Spring initializr to bootstrap the project quickly.
Our application will be organized around 3 main layers:
Domain Student.java
Repository StudentRepository.java
Service StudentService.java
Create Domain Model
First, we are going to create the domain model. For instance, let’s consider the Student.java:
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String firstName;
private String lastName;
private int age;
private String gender;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
}
Create JPA Repository
Secondarily, let’s create a Spring Data JPA repository for our domain Student:
@Repository
public interface StudentRepository extends JpaRepository<Student, Integer> {
}
In short, StudentRepository exposes basic CRUD operations for the Student class.
Create a Business Service
Lastly, we will create a simple interface to encapsulate the business logic:
public interface StudentService {
List<Student> findAll();
Optional<Student> findById(int id);
Student save(Student student);
void deleteById(int id);
}
Now, let’s create a concrete implementation for our interface:
@Service
public class StudentServiceImpl implements StudentService {
private final StudentRepository studentRepository;
public StudentServiceImpl(StudentRepository studentRepository) {
this.studentRepository = studentRepository;
}
@Override
public List<Student> findAll() {
return studentRepository.findAll();
}
@Override
public Optional<Student> findById(int id) {
return studentRepository.findById(id);
}
@Override
public Student save(Student student) {
return studentRepository.save(student);
}
@Override
public void deleteById(int id) {
studentRepository.deleteById(id);
}
}
As we can see, StudentServiceImpl relies on StudentRepository to perform data access logic. This is why we injected it as a dependency.
Unit Testing Service Layer
Now that we put all the pieces together, let’s see how to implement unit testing for StudentServiceImpl.
As shown above, StudentRepository is injected implicitly using the parametrized constructor.
So, in order to test the service, we need first to mock the repository. This is where Mockito comes to the rescue.
Please refer to our article on how to unit test a Spring Boot API for more detailed informations.
Mock Repository using Mockito
Mockito comes with a host of ready-to-use methods and annotations to do all the heavy lifting of mocking objects.
In short, Mockito offers two ways to create a mock for a repository:
@Mock annotation
Static method mock()
So, let’s take a close look at each option.
Using @Mock
Now, let’s move on to the unit test. First, we will be using the @Mock annotation to mock StudentRepository.
@ExtendWith(MockitoExtension.class)
class StudentServiceUnitTest {
@Mock
private StudentRepository studentRepository;
@InjectMocks
private StudentServiceImpl studentService;
}
@ExtendWith(MockitoExtension.class) enables Mockito support
@InjectMocks allows to create studentService and inject the mocked studentRepository into it
For instance, let’s add a test case to test the findAll() method:
@Test
void findAll_should_return_student_list() {
// Given
Student student = new Student();
student.setId(1);
student.setFirstName("Abderrahim");
student.setLastName("Azhrioun");
student.setAge(20);
student.setGender("Male");
// When calling the mocked repository method
when(studentRepository.findAll()).thenReturn(List.of(student));
List students = this.studentService.findAll();
// Then
assertEquals(List.of(student), students);
verify(this.studentRepository).findAll();
}
Another solution would be using MockitoAnnotations.initMocks(this) to initialize the annotated mocked objects. However, this method is marked as deprecated.
Using Mockito.mock()
Now let’s go ahead and see how we can use the Mockito.mock() method to achieve the same objective:
class StudentServiceUnitTestV2 {
private StudentRepository studentRepository;
private StudentServiceImpl studentService;
@BeforeEach
void setup() {
studentRepository = Mockito.mock(StudentRepository.class);
studentService = new StudentServiceImpl(studentRepository);
}
}
The method takes the class of the object to mock as a parameter. This is why we passed StudentRepository.class.
Mocking Repository that Returns Optional
Typically, findById() returns an Optional object unlike findAll() which return a simple list.
So, how we can tell the mocked repository to return an Optional when invoking findById()?
To answer this question, we are going to create a test case:
@Test
void findById_should_return_single_student() {
// Given
Student student = new Student();
student.setId(2);
student.setFirstName("Emma");
student.setGender("Female");
// When calling findById returns Optional
when(studentRepository.findById(anyInt())).thenReturn(Optional.of(student));
Optional<Student> returnedStudent = this.studentService.findById(2);
// Then
assertTrue(returnedStudent.isPresent());
verify(this.studentRepository).findById(2);
}
Please notice that we used Optional.of(student) to tell thenReturn() to return an Optional when findById() is called.
Conclusion
In this tutorial, we explored different ways to mock a repository in Spring Boot using Mockito.
First, we created a simple service that uses a JPA repository. Then, we explained how to mock the injected repository using practical examples.