Spring Boot Mockito - @Mock & @InjectMocks Example

In this tutorial, we will learn about the @Mock and @InjectMocks annotation of Mockito framework, and at the end, we will see how the Spring Boot application can utilize these annotation for unit testing with JUnit 5. Therefore, read the post till the end.

Mockito

Mocking framework Mockito is used for efficient unit testing in Java-based applications. It is used in conjunction with  testing framework JUnit. We construct a mock with Mockito, instruct it on what to do when certain methods are called on it, and then utilize the mock instance rather than the real one in our test.


@Mock

A mock object is created for a specified class or interface using the @Mock annotation. It gives Mockito instructions on how to make a proxy object that behaves just like the original object. We can mimic the actions of dependencies without calling their real methods by using @Mock.

Here’s an example of using @Mock:

@ExtendWith(MockitoExtension.class)
public class UserServiceTests {

@Mock
private UserRepository userRepository;

//TODO
}

In the above example, Mockito creates a mock object for the UserRepository interface.


@InjectMocks

@InjectMocks creates an instance of the class and injects the mocks that are created with the @Mock annotation into this instance.

Here’s an example of using @InjectMocks:

@ExtendWith(MockitoExtension.class)
public class UserServiceTests {

@InjectMocks
private UserService userService;

@Mock
private UserRepository userRepository;

//Todo
}


Complete Example - Unit testing Spring Boot application with Mockito and JUnit 5

Next we will create a spring boot JPA application, create a repository layer, service layer, and controller layer. Finally we will do unit testing with help of Mockito@Mock, and @InjectMocks annotation to verify our system is working as expected.


Creating a spring boot application

First, open the Spring initializr https://start.spring.io

Then, Provide the Group and Artifact name. We have provided Group name com.knf.dev.demo and Artifact spring-mockito-mock-injectmocks-example. Here I selected the Maven project - language Java 17 - Spring Boot 3.2.5Spring Data JPA, Spring Web and H2 Database.


Final Project Directory


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.2.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.knf.dev.demo</groupId>
<artifactId>spring-mockito-mock-injectmocks-example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-mockito-mock-injectmocks-example</name>
<description>Demo project for Spring Boot</description>
<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.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>

spring-boot-starter-test starter will provide following libraries:

  • JUnit 
  • Spring Test & Spring Boot Test 
  • AssertJ
  • Hamcrest 
  • Mockito 
  • JSONassert 
  • JsonPath 


Create User Entity

A User object as JPA entity. I am not a big fan of Project Lombok; therefore, getters and setters are explicitly added.

package com.knf.dev.demo.entity;

import jakarta.persistence.*;

@Entity
@Table(name = "users")
public class User {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(nullable = false)
private String firstName;
@Column(nullable = false)
private String lastName;
@Column(nullable = false, unique = true)
private String email;

public Long getId() {
return id;
}

public void setId(Long 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 String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

public User() {
}

public User(Long id, String firstName, String lastName, String email) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}
}

The @Entity annotation specifies that the class is an entity and is mapped to a database table. 

The @Table annotation specifies the name of the database table to be used for mapping. 

The @Id annotation specifies the primary key of an entity and the @GeneratedValue provides for the specification of generation strategies for the values of primary keys.


Create User Repository

package com.knf.dev.demo.repository;

import com.knf.dev.demo.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {
}
JpaRepository is a JPA-specific extension of Repository. It contains an API for basic CRUD operations and also API for pagination and sorting.


Create User Service

package com.knf.dev.demo.service;

import com.knf.dev.demo.entity.User;
import com.knf.dev.demo.repository.UserRepository;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

@Service
public class UserService {

private final UserRepository userRepository;

public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}

public User createUser(User user) {
return userRepository.save(user);
}


public User getUserById(Long userId) {
Optional<User> optionalUser = userRepository.findById(userId);
return optionalUser.get();
}

public List<User> getAllUsers() {
return userRepository.findAll();
}
}


Create User Controller

package com.knf.dev.demo.controller;

import com.knf.dev.demo.entity.User;
import com.knf.dev.demo.service.UserService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/users")
public class UserController {

private final UserService userService;

public UserController(UserService userService) {
this.userService = userService;
}

@PostMapping
public ResponseEntity<User> createUser(@RequestBody User user) {
User savedUser = userService.createUser(user);
return new ResponseEntity<>(savedUser, HttpStatus.CREATED);
}

@GetMapping("{id}")
public ResponseEntity<User> getUserById(@PathVariable("id") Long userId) {
User user = userService.getUserById(userId);
return new ResponseEntity<>(user, HttpStatus.OK);
}

@GetMapping
public ResponseEntity<List<User>> getAllUsers() {
List<User> users = userService.getAllUsers();
return new ResponseEntity<>(users, HttpStatus.OK);
}
}

The @RestController annotation is mainly utilized for building restful web services utilizing Spring MVC. It is a convenience annotation, this annotation itself annotated with @ResponseBody and @Controller annotation. The class annotated with @RestController annotation returns JSON replication in all the methods. 

@RequestMapping is used to map web requests onto specific handler classes and/or handler methods. @RequestMapping can be applied to the controller class as well as methods.

@GetMapping annotation for mapping HTTP GET requests onto specific handler methods.


Driver class

package com.knf.dev.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}

}


Implementing the Tests

@ExtendWith(MockitoExtension.class)@ExtendWith annotation is used to register extensions for Junit 5 test, MockitoExtension.class allows test to initialize mocks and leverage Mockito's features in JUnit 5 tests.

@ExtendWith(MockitoExtension.class) is equivalent of @RunWith(MockitoJUnitRunner.class) of the JUnit4


Unit Testing User Controller

package com.knf.dev.demo.controller;

import com.knf.dev.demo.entity.User;
import com.knf.dev.demo.service.UserService;
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 java.util.ArrayList;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
public class UserControllerTests {

@Mock
private UserService userService;

@InjectMocks
private UserController userController;

@Test
void testFindAllUsers() {

List<User> list = new ArrayList<>();
User userOne = new User(1l,"John", "John","john@hmail.com");
User userTwo = new User(2l,"Alpha", "Alpha","alpha@hmail.com");
User userThree = new User(3l,"Beta", "Beta","beta@hmail.com");

list.add(userOne);
list.add(userTwo);
list.add(userThree);

when(userService.getAllUsers()).thenReturn(list);

ResponseEntity<List<User>> users = userController.getAllUsers();

assertEquals(3, users.getBody().size());
}

@Test
void testCreateUser() {

User user = new User(1l,"John", "John","john@hmail.com");

when(userService.createUser(user)).thenReturn(user);

ResponseEntity<User> user1 = userController.createUser(user);

assertEquals("john@hmail.com", user1.getBody().getEmail());
}

@Test
void testfindUserById() {

User user = new User(1l,"John", "John","john@hmail.com");

when(userService.getUserById(1l)).thenReturn(user);

ResponseEntity<User> user1 = userController.getUserById(1l);

assertEquals("john@hmail.com", user1.getBody().getEmail());
}
}


Unit Testing User Service

package com.knf.dev.demo.service;

import com.knf.dev.demo.entity.User;
import com.knf.dev.demo.repository.UserRepository;
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.ArrayList;
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 UserServiceTests {

@InjectMocks
private UserService userService;

@Mock
private UserRepository userRepository;

@Test
void testFindAllUsers() {

List<User> list = new ArrayList<>();
User userOne = new User(1l,"John", "John","john@hmail.com");
User userTwo = new User(2l,"Alpha", "Alpha","alpha@hmail.com");
User userThree = new User(3l,"Beta", "Beta","beta@hmail.com");

list.add(userOne);
list.add(userTwo);
list.add(userThree);

when(userRepository.findAll()).thenReturn(list);

List<User> allUsers = userService.getAllUsers();

assertEquals(3, allUsers.size());
}

@Test
void testCreateUser() {

User user = new User(1l,"John", "John","john@hmail.com");

when(userRepository.save(user)).thenReturn(user);

User user1 = userService.createUser(user);

assertEquals("john@hmail.com", user1.getEmail());
}

@Test
void testfindUserById() {

User user = new User(1l,"John", "John","john@hmail.com");

when(userRepository.findById(1l)).thenReturn(Optional.of(user));

User user1 = userService.getUserById(1l);

assertEquals("john@hmail.com", user1.getEmail());
}
}


Run the test

mvn test

Popular posts from this blog

Learn Java 8 streams with an example - print odd/even numbers from Array and List

Java Stream API - How to convert List of objects to another List of objects using Java streams?

Registration and Login with Spring Boot + Spring Security + Thymeleaf

Java, Spring Boot Mini Project - Library Management System - Download

ReactJS, Spring Boot JWT Authentication Example

Top 5 Java ORM tools - 2024

Java - Blowfish Encryption and decryption Example

Spring boot video streaming example-HTML5

Google Cloud Storage + Spring Boot - File Upload, Download, and Delete