Show List
Testing Spring Boot Application Using Mockito
In this demo we are going to create a Spring Boot application and then write a test using Mockito.
Creating the Spring Boot Application
Here is the structure of the project we are going to create for this example
1. Go to Spring initializr website and create a Java Maven Project with dependencies: H2, Spring Data JPA and Web. Download the project zip and extract to a folder.
2. Import the project into IDE (I am using IntelliJ Idea). Add the junit dependency in the Pom.xml as below.
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.6.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Here is the Student model class. Each Student object will have a name and grade.
Student.java
package com.example.demo.model;
import javax.persistence.*;
@Entity
@Table
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int student_id;
private String name;
private String grade;
public Student(){
}
public Student( String name, String grade) {
this.name = name;
this.grade = grade;
}
public int getStudent_id() {
return student_id;
}
public void setStudent_id(int student_id) {
this.student_id = student_id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGrade() {
return grade;
}
public void setGrade(String grade) {
this.grade = grade;
}
}
We are using CrudRepository interface to store the data in the in memory H2 database.
StudentRepo.java
package com.example.demo.dao;
import com.example.demo.model.Student;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface StudentRepo extends CrudRepository<Student, Long> {}
StudentService class calls the StudentRepo for database operations.
StudentService.java
package com.example.demo.service;
import com.example.demo.dao.StudentRepo;
import com.example.demo.model.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Optional;
@Service
public class StudentService {
@Autowired
private StudentRepo repo;
public Iterable<Student> findAll(){
return repo.findAll();
}
public Optional<Student> findById(Long id) {
return repo.findById(id);
}
public Student save(Student newStudent) {
return repo.save(newStudent);
}
public void deleteById(Long id) {
repo.deleteById(id);
}
}
Here is the controller for the application. We are exposing the endpoints to add, update, remove and get student information. Controller calls the StudentService class for interacting with database.
StudentController.java
package com.example.demo.controller;
import com.example.demo.model.Student;
import com.example.demo.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Optional;
@RestController
public class StudentController {
@Autowired
private StudentService service;
@GetMapping("/students")
private List<Student> getAllStudents(){
return (List<Student>) service.findAll();
}
@GetMapping("/student/{id}")
private Optional<Student> getStudents(@PathVariable Long id){
return service.findById(id);
}
@PostMapping("/students")
private Student addStudent(@RequestBody Student newStudent){
return service.save(newStudent);
}
@DeleteMapping("/students/{id}")
private void removeStudent(@PathVariable Long id){
service.deleteById(id);
}
@PutMapping("/students/{id}")
private Student updateStudent(@RequestBody Student newStudent, @PathVariable Long id){
return service.findById(id)
.map(student -> {
student.setName(newStudent.getName());
student.setGrade(newStudent.getGrade());
return service.save(student);
})
.orElseGet(() -> {
newStudent.setStudent_id(Math.toIntExact(id));
return service.save(newStudent);
});
}
}
LoadData class is to load the initial data when the application starts.
LoadData.java
package com.example.demo.dataload;
import com.example.demo.dao.StudentRepo;
import com.example.demo.model.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Configuration;
@Configuration
public class LoadData implements ApplicationRunner {
@Autowired
StudentRepo repo;
@Override
public void run(ApplicationArguments args) throws Exception {
repo.save(new Student("Ana", "One"));
repo.save(new Student("Bob", "Two"));
repo.save(new Student("Charlie", "One"));
repo.save(new Student("David", "Three"));
}
}
Here is the SpringBoot class with main method.
DemoApplication.java
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
Creating the Test Class with Mockito
Mockito helps to test the code without depending on the actual implementation of the dependent classes or interfaces. In the application we have a dependency on the database. In this test example below we are going to return the mock data to service as if it was coming from the database.
DemoApplicationTests.java
package com.example.demo;
import com.example.demo.dao.StudentRepo;
import com.example.demo.model.Student;
import com.example.demo.service.StudentService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.Arrays;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.*;
@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {
@Mock
private StudentRepo mockStudentRepo;
@InjectMocks
private StudentService myService;
@Test
public void testGetData() {
// Arrange
List<Student> expectedData = Arrays.asList(new Student("Mike", "Two"));
when(mockStudentRepo.findAll()).thenReturn(expectedData);
// Act
Iterable<Student> actualData = myService.findAll();
// Assert
assertEquals(expectedData, actualData);
verify(mockStudentRepo, times(1)).findAll();
}
}
In this example, the test class is annotated with @RunWith(SpringRunner.class) and @SpringBootTest to indicate that it is a Spring Boot test. The StudentRepo class is mocked using the @Mock annotation, and the StudentService class is injected using the @InjectMocks annotation.
In the test method testGetData(), the expected data is created, and the when(mockStudentRepo.findAll()).thenReturn(expectedData) line is used to specify that when the findAll() method of the mockStudentRepo is called, it should return the expected data.
The myService.findAll() method is then called, and the resulting data is stored in the actualData variable. The test then asserts that the expected data and the actual data are equal, and verifies that the findAll() method of the mockStudentRepo was called exactly once using the verify(mockStudentRepo, times(1)).findAll() line.
Source Code:
https://github.com/it-code-lab/SpringBootMockitoTest
Leave a Comment