Prerequisites
- JDK 17 or later
- Maven or Gradle
- IDE (IntelliJ IDEA, Eclipse, etc.)
Setting Up the Project
Step 1: Create a New Spring Boot Project
Use Spring Initializr to create a new project with the following dependencies:
- Spring Web
- Spring Data JPA
- H2 Database
- Spring Boot Starter Test
Download and unzip the project, then open it in your IDE.
Step 2: Define the Entity, Repository, Service, and Controller
2.1 Create the Student
Entity
Create a class named Student
in the com.example.demo.entity
package.
package com.example.demo.entity;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
// Getters and setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
Explanation:
@Entity
: Marks the class as a JPA entity.@Id
and@GeneratedValue
: Define the primary key and its generation strategy.name
andemail
: Simple fields representing the student's name and email.
2.2 Create the StudentRepository
Create an interface named StudentRepository
in the com.example.demo.repository
package.
package com.example.demo.repository;
import com.example.demo.entity.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface StudentRepository extends JpaRepository<Student, Long> {
}
Explanation:
JpaRepository<Student, Long>
: Provides CRUD operations for theStudent
entity.@Repository
: Marks the interface as a Spring Data repository.
2.3 Create the StudentService
Create a service class named StudentService
in the com.example.demo.service
package.
package com.example.demo.service;
import com.example.demo.entity.Student;
import com.example.demo.repository.StudentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class StudentService {
@Autowired
private StudentRepository studentRepository;
public List<Student> getAllStudents() {
return studentRepository.findAll();
}
public Optional<Student> getStudentById(Long id) {
return studentRepository.findById(id);
}
public Student createStudent(Student student) {
return studentRepository.save(student);
}
public void deleteStudent(Long id) {
studentRepository.deleteById(id);
}
}
Explanation:
@Service
: Marks the class as a service component in Spring.@Autowired
: Injects theStudentRepository
dependency.getAllStudents()
,getStudentById(Long id)
,createStudent(Student student)
,deleteStudent(Long id)
: Methods to perform CRUD operations onStudent
entities.
2.4 Create the StudentController
Create a controller class named StudentController
in the com.example.demo.controller
package.
package com.example.demo.controller;
import com.example.demo.entity.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
@RequestMapping("/students")
public class StudentController {
@Autowired
private StudentService studentService;
@GetMapping
public List<Student> getAllStudents() {
return studentService.getAllStudents();
}
@GetMapping("/{id}")
public Optional<Student> getStudentById(@PathVariable Long id) {
return studentService.getStudentById(id);
}
@PostMapping
public Student createStudent(@RequestBody Student student) {
return studentService.createStudent(student);
}
@DeleteMapping("/{id}")
public void deleteStudent(@PathVariable Long id) {
studentService.deleteStudent(id);
}
}
Explanation:
@RestController
: Marks the class as a REST controller.@RequestMapping("/students")
: Maps the controller to/students
endpoint.@Autowired
: Injects theStudentService
dependency.@GetMapping
,@PostMapping
,@DeleteMapping
: Maps HTTP GET, POST, and DELETE requests respectively.
Writing Unit Tests
Unit tests focus on testing individual components in isolation. Spring Boot provides support for writing unit tests with the help of JUnit and Mockito.
Step 3: Write Unit Tests for the Service Layer
3.1 Write Unit Tests for StudentService
Create a test class named StudentServiceTest
in the src/test/java/com/example/demo/service
package.
package com.example.demo.service;
import com.example.demo.entity.Student;
import com.example.demo.repository.StudentRepository;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
public class StudentServiceTest {
@Mock
private StudentRepository studentRepository;
@InjectMocks
private StudentService studentService;
@Test
void testGetAllStudents() {
Student student1 = new Student();
student1.setName("John Doe");
student1.setEmail("john.doe@example.com");
Student student2 = new Student();
student2.setName("Jane Doe");
student2.setEmail("jane.doe@example.com");
List<Student> students = Arrays.asList(student1, student2);
when(studentRepository.findAll()).thenReturn(students);
List<Student> result = studentService.getAllStudents();
assertEquals(2, result.size());
verify(studentRepository, times(1)).findAll();
}
@Test
void testGetStudentById() {
Student student = new Student();
student.setId(1L);
student.setName("John Doe");
student.setEmail("john.doe@example.com");
when(studentRepository.findById(1L)).thenReturn(Optional.of(student));
Optional<Student> result = studentService.getStudentById(1L);
assertEquals("John Doe", result.get().getName());
assertEquals("john.doe@example.com", result.get().getEmail());
verify(studentRepository, times(1)).findById(1L);
}
@Test
void testCreateStudent() {
Student student = new Student();
student.setName("John Doe");
student.setEmail("john.doe@example.com");
when(studentRepository.save(student)).thenReturn(student);
Student result = studentService.createStudent(student);
assertEquals("John Doe", result.getName());
assertEquals("john.doe@example.com", result.getEmail());
verify(studentRepository, times(1)).save(student);
}
@Test
void testDeleteStudent() {
Long studentId = 1L;
doNothing().when(studentRepository).deleteById(studentId);
studentService.deleteStudent(studentId);
verify(studentRepository, times(1)).deleteById(studentId);
}
}
Explanation:
@ExtendWith(MockitoExtension.class)
: Tells JUnit to use the Mockito extension.@Mock
: Creates a mock instance ofStudentRepository
.@InjectMocks
: Injects the mocks intoStudentService
.when
,thenReturn
,verify
: Methods from Mockito to define behavior and verify interactions.
Writing Integration Tests
Integration tests verify the interaction between different components of the application. Spring Boot provides support for writing integration tests with the help of the @SpringBootTest
annotation.
Step 4: Write Integration Tests
4.1 Create the Integration Test Class
Create a test class named StudentControllerIntegrationTest
in the src/test/java/com/example/demo/controller
package.
package com.example.demo.controller;
import com.example.demo.entity.Student;
import com.example.demo.repository.StudentRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import java.util.Optional;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@SpringBootTest
@AutoConfigureMockMvc
public class StudentControllerIntegrationTest {
@Autowired
private MockMvc mockMvc
;
@Autowired
private StudentRepository studentRepository;
private Student student;
@BeforeEach
public void setUp() {
studentRepository.deleteAll();
student = new Student();
student.setName("John Doe");
student.setEmail("john.doe@example.com");
studentRepository.save(student);
}
@Test
public void testGetAllStudents() throws Exception {
mockMvc.perform(get("/students")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$[0].name", is(student.getName())))
.andExpect(jsonPath("$[0].email", is(student.getEmail())));
}
@Test
public void testGetStudentById() throws Exception {
mockMvc.perform(get("/students/{id}", student.getId())
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name", is(student.getName())))
.andExpect(jsonPath("$.email", is(student.getEmail())));
}
@Test
public void testCreateStudent() throws Exception {
mockMvc.perform(post("/students")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"name\": \"Jane Doe\", \"email\": \"jane.doe@example.com\"}"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name", is("Jane Doe")))
.andExpect(jsonPath("$.email", is("jane.doe@example.com")));
}
@Test
public void testDeleteStudent() throws Exception {
mockMvc.perform(delete("/students/{id}", student.getId())
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
Optional<Student> deletedStudent = studentRepository.findById(student.getId());
assertEquals(Optional.empty(), deletedStudent);
}
}
Explanation:
@SpringBootTest
: Tells Spring Boot to look for the main configuration class and start the application context.@AutoConfigureMockMvc
: Configures MockMvc for testing MVC controllers.MockMvc
: Mocks the servlet environment to test Spring MVC controllers.@BeforeEach
: Sets up the database state before each test.mockMvc.perform
,andExpect
: Methods from MockMvc to send requests and verify responses.
Running the Tests
Run the tests using your IDE or from the command line with Maven:
./mvnw test
Conclusion
In this comprehensive guide, you have learned how to set up and run tests in a Spring Boot 3.2 application. We covered:
- Setting up a Spring Boot project for testing.
- Creating an entity, repository, service, and controller.
- Writing unit tests for the service layer using JUnit and Mockito.
- Writing integration tests for the controller layer using MockMvc and
@SpringBootTest
.
By following these steps, you can ensure your Spring Boot applications are well-tested and reliable.
Comments
Post a Comment
Leave Comment