Mockito @Mock Annotation Example

Introduction

The @Mock annotation is a shorthand way of creating mock objects. Instead of manually creating a mock using Mockito.mock(Class), you can annotate a field with @Mock to automatically create a mock instance.

In many software applications, business logic and data access logic are separated into service and repository layers, respectively. When testing the service layer, it's often beneficial to mock the repository to ensure that it is tested in isolation. 

This tutorial will demonstrate step-by-step how to mock the EmployeeService and EmployeeRepository using Mockito's @Mock annotation and the Given/When/Then format. 

Maven Dependencies

To use Mockito with JUnit 5, add the following dependencies to your pom.xml file:

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>4.8.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-junit-jupiter</artifactId>
    <version>4.8.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-engine</artifactId>
    <version>5.9.2</version>
    <scope>test</scope>
</dependency>

Step-by-Step Example

Step 1: Create the Employee and EmployeeRepository Classes

First, create the Employee class and the EmployeeRepository interface.

public class Employee {
    private String name;
    private String position;

    // Constructor
    public Employee(String name, String position) {
        this.name = name;
        this.position = position;
    }

    // Getters and Setters
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPosition() {
        return position;
    }

    public void setPosition(String position) {
        this.position = position;
    }
}

public interface EmployeeRepository {
    Employee findEmployeeByName(String name);
}

Step 2: Create the EmployeeService Class

Create the EmployeeService class that depends on the EmployeeRepository.

public class EmployeeService {
    private final EmployeeRepository employeeRepository;

    public EmployeeService(EmployeeRepository employeeRepository) {
        this.employeeRepository = employeeRepository;
    }

    public Employee getEmployee(String name) {
        return employeeRepository.findEmployeeByName(name);
    }
}

Step 3: Set Up JUnit 5 Test Class with Mockito

Create a test class for EmployeeService using JUnit 5 and Mockito.

import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.junit.jupiter.api.extension.ExtendWith;

@ExtendWith(MockitoExtension.class)
public class EmployeeServiceTest {

    @Mock
    private EmployeeRepository employeeRepository;

    @InjectMocks
    private EmployeeService employeeService;

    @Test
    public void testGetEmployee() {
        // Given
        Employee mockEmployee = new Employee("John Doe", "Developer");
        when(employeeRepository.findEmployeeByName("John Doe")).thenReturn(mockEmployee);

        // When
        Employee result = employeeService.getEmployee("John Doe");

        // Then
        assertNotNull(result);
        assertEquals("John Doe", result.getName());
        assertEquals("Developer", result.getPosition());
        verify(employeeRepository).findEmployeeByName("John Doe");
    }
}

Explanation

  1. Annotations:

    • @ExtendWith(MockitoExtension.class): Integrates Mockito with JUnit 5, enabling the use of Mockito annotations.
    • @Mock: Creates a mock instance of the EmployeeRepository interface.
    • @InjectMocks: Injects the mock EmployeeRepository into the EmployeeService instance.
  2. Given:

    • Employee mockEmployee = new Employee("John Doe", "Developer");: Creates a mock Employee object.
    • when(employeeRepository.findEmployeeByName("John Doe")).thenReturn(mockEmployee);: Configures the mock EmployeeRepository to return the mock Employee when the findEmployeeByName method is called with the argument "John Doe".
  3. When:

    • Employee result = employeeService.getEmployee("John Doe");: Calls the getEmployee method on the EmployeeService instance.
  4. Then:

    • assertNotNull(result);: Asserts that the result is not null.
    • assertEquals("John Doe", result.getName());: Asserts that the name of the returned Employee is "John Doe".
    • assertEquals("Developer", result.getPosition());: Asserts that the position of the returned Employee is "Developer".
    • verify(employeeRepository).findEmployeeByName("John Doe");: Verifies that the findEmployeeByName method was called with the expected argument.

Additional Scenarios

Scenario 1: Employee Not Found

In this scenario, we will test the case where the employee is not found in the repository.

@Test
public void testGetEmployee_NotFound() {
    // Given
    when(employeeRepository.findEmployeeByName("Jane Doe")).thenReturn(null);

    // When
    Employee result = employeeService.getEmployee("Jane Doe");

    // Then
    assertNull(result);
    verify(employeeRepository).findEmployeeByName("Jane Doe");
}

Scenario 2: Employee with Different Position

In this scenario, we will test the case where the employee's position is different from the expected value.

@Test
public void testGetEmployee_DifferentPosition() {
    // Given
    Employee mockEmployee = new Employee("John Doe", "Manager");
    when(employeeRepository.findEmployeeByName("John Doe")).thenReturn(mockEmployee);

    // When
    Employee result = employeeService.getEmployee("John Doe");

    // Then
    assertNotNull(result);
    assertEquals("John Doe", result.getName());
    assertEquals("Manager", result.getPosition());
    verify(employeeRepository).findEmployeeByName("John Doe");
}

Conclusion

The @Mock annotation in Mockito simplifies the creation and injection of mock objects in unit tests. By using @Mock and @InjectMocks, you can easily set up mock dependencies and focus on testing the behavior of your code. This step-by-step guide covered different scenarios using the Given/When/Then format to demonstrate how to effectively use the @Mock annotation in your unit tests.

Related Mockito Annotations

Comments