Introduction
Are you still afraid of writing tests? Do you think it’s complicated and time-consuming? Relax! It’s much easier than it seems. With Mockito, we can easily create isolated tests that help us verify service operations without touching the real database. In this article, we’ll explore how to properly use @Mock
and @InjectMocks
to make your code reliable and your tests fast and efficient. Let’s go!
What is Mockito?
Mockito is a popular framework for creating mock objects in Java applications. Mocks are used to simulate dependencies, allowing you to test individual components without real interactions with the database, external APIs, or other modules.
Key Mockito Annotations
@Mock – Creates a mock object for a specified class or interface. It allows replacing the real behavior of dependencies.
@InjectMocks – Creates an instance of the class under test and automatically injects dependencies annotated with@Mock
.
@ExtendWith(MockitoExtension.class) – Integrates Mockito with JUnit 5, enabling the use of@Mock
and@InjectMocks
without additional setup.
Example usage:
@ExtendWith(MockitoExtension.class) public class DeviceServiceTest { @Mock private DeviceRepository deviceRepository; @InjectMocks private DeviceService deviceService; }
Project Setup
To get started, create a Spring Boot project using Spring Initializr with the following dependencies:
- Spring Web – to create REST APIs.
- Spring Data JPA – for database interaction.
- H2 Database – an in-memory database for testing.
- Lombok – to reduce boilerplate code.
- Spring Boot Starter Test – includes Mockito, JUnit, and other testing libraries.
Complete 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>3.4.3</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>tech.devblueprint</groupId> <artifactId>mock-testing-example</artifactId> <version>0.0.1-SNAPSHOT</version> <name>mock-testing-example</name> <description>Demonstration of Mockito Mock and InjectMocks usage in Spring Boot</description> <url/> <licenses> <license/> </licenses> <developers> <developer/> </developers> <scm> <connection/> <developerConnection/> <tag/> <url/> </scm> <properties> <java.version>17</java.version> </properties> <dependencies> <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>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>17</source> <target>17</target> <annotationProcessorPaths> <path> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> </path> </annotationProcessorPaths> </configuration> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
Now, let’s create the business logic, including Entity, Repository, Service, and Controller.
1. Creating the Device Entity
package tech.devblueprint.mock_testing_example.entity; import jakarta.persistence.*; import lombok.*; @Entity @Table(name = "devices") @Getter @Setter @NoArgsConstructor @AllArgsConstructor public class Device { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false, unique = true) private String name; @Column(nullable = false) private String type; @Column(nullable = false) private boolean active; }
2. Creating the Repository
package tech.devblueprint.mock_testing_example.repository; import org.springframework.data.jpa.repository.JpaRepository; import tech.devblueprint.mock_testing_example.entity.Device; public interface DeviceRepository extends JpaRepository<Device, Long> { }
3. Creating the Service Layer
package tech.devblueprint.mock_testing_example.service; import org.springframework.stereotype.Service; import tech.devblueprint.mock_testing_example.entity.Device; import tech.devblueprint.mock_testing_example.repository.DeviceRepository; import java.util.List; import java.util.Optional; @Service public class DeviceService { private final DeviceRepository deviceRepository; public DeviceService(DeviceRepository deviceRepository) { this.deviceRepository = deviceRepository; } public Device createDevice(Device device) { return deviceRepository.save(device); } public Device getDeviceById(Long id) { Optional<Device> device = deviceRepository.findById(id); return device.orElse(null); } public List<Device> getAllDevices() { return deviceRepository.findAll(); } }
4. Creating the REST Controller
package tech.devblueprint.mock_testing_example.controller; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import tech.devblueprint.mock_testing_example.entity.Device; import tech.devblueprint.mock_testing_example.service.DeviceService; import java.util.List; @RestController @RequestMapping("/api/devices") public class DeviceController { private final DeviceService deviceService; public DeviceController(DeviceService deviceService) { this.deviceService = deviceService; } @PostMapping public ResponseEntity<Device> createDevice(@RequestBody Device device) { return ResponseEntity.ok(deviceService.createDevice(device)); } @GetMapping("/{id}") public ResponseEntity<Device> getDeviceById(@PathVariable Long id) { return ResponseEntity.ok(deviceService.getDeviceById(id)); } @GetMapping public ResponseEntity<List<Device>> getAllDevices() { return ResponseEntity.ok(deviceService.getAllDevices()); } }
Thus, we have a working REST API for managing devices.
Writing Tests
Now, let’s test our code using Mockito and JUnit 5.
1. Testing the Controller
package tech.devblueprint.mock_testing_example.controller; 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 org.springframework.http.ResponseEntity; import tech.devblueprint.mock_testing_example.entity.Device; import tech.devblueprint.mock_testing_example.service.DeviceService; import java.util.List; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class DeviceControllerTest { @Mock private DeviceService deviceService; @InjectMocks private DeviceController deviceController; @Test void testFindAllDevices() { List<Device> devices = List.of( new Device(1L, "Laptop", "Electronics", true), new Device(2L, "Smartphone", "Electronics", true) ); when(deviceService.getAllDevices()).thenReturn(devices); ResponseEntity<List<Device>> response = deviceController.getAllDevices(); assertEquals(2, response.getBody().size()); } @Test void testCreateDevice() { Device device = new Device(1L, "Laptop", "Electronics", true); when(deviceService.createDevice(device)).thenReturn(device); ResponseEntity<Device> response = deviceController.createDevice(device); assertEquals("Laptop", response.getBody().getName()); } @Test void testFindDeviceById() { Device device = new Device(1L, "Laptop", "Electronics", true); when(deviceService.getDeviceById(1L)).thenReturn(device); ResponseEntity<Device> response = deviceController.getDeviceById(1L); assertEquals("Laptop", response.getBody().getName()); } }
2. Testing the Service Layer
package tech.devblueprint.mock_testing_example.service; 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 tech.devblueprint.mock_testing_example.entity.Device; import tech.devblueprint.mock_testing_example.repository.DeviceRepository; import java.util.List; import java.util.Optional; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) public class DeviceServiceTest { @InjectMocks private DeviceService deviceService; @Mock private DeviceRepository deviceRepository; @Test void testFindAllDevices() { List<Device> devices = List.of( new Device(1L, "Laptop", "Electronics", true), new Device(2L, "Smartphone", "Electronics", true) ); when(deviceRepository.findAll()).thenReturn(devices); List<Device> result = deviceService.getAllDevices(); assertEquals(2, result.size()); } @Test void testCreateDevice() { Device device = new Device(1L, "Laptop", "Electronics", true); when(deviceRepository.save(device)).thenReturn(device); Device result = deviceService.createDevice(device); assertEquals("Laptop", result.getName()); } @Test void testFindDeviceById() { Device device = new Device(1L, "Laptop", "Electronics", true); when(deviceRepository.findById(1L)).thenReturn(Optional.of(device)); Device result = deviceService.getDeviceById(1L); assertEquals("Laptop", result.getName()); } }
We used mock objects to replace dependencies and verified that the service operates correctly.
Conclusion
In this article, we explored how to use Mockito in Spring Boot, implemented the business logic for a REST API, and tested it using @Mock and @InjectMocks. This approach allows us to create isolated and efficient unit tests, improving application reliability.
Now you can apply Mockito in your projects and test your code more effectively! 🚀