Mockito Annotations with Examples - @Mock, @InjectMocks, @Spy, @Captor, and @ExtendWith

1. Overview

Mockito is one of the most popular mocking libraries in Java, and its annotations offer concise ways of creating and managing mock objects. In this tutorial, we'll explore the core annotations of Mockito with practical examples centered around an Employee Management System.

Mockito Annotations

1. @Mock: Creates a mock object.

2. @InjectMocks: Injects the mock objects to the mocked object instance.

3. @Spy: Allows spying on a real object. You can stub some methods while keeping the real methods' behavior for non-stubbed ones.

4. @Captor: Captures argument values for further assertions.

5. @ExtendWith(MockitoExtension.class): For integrating Mockito with JUnit 5.

2. Development Steps

1. Set up the necessary dependencies.

2. Define the model, service, and repository classes.

3. Implement a test class illustrating each annotation's usage.

4. Run the tests and understand the outcomes.

3. Dependencies (Mockito and JUnit 5)

<dependencies>
    <!-- JUnit 5 -->
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <version>5.7.0</version>
        <scope>test</scope>
    </dependency>
    <!-- Mockito -->
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-junit-jupiter</artifactId>
        <version>3.11.2</version>
        <scope>test</scope>
    </dependency>
</dependencies>

4. Code Program

// Model
public class Employee {
    private Long id;
    private String name;
    // getters, setters, constructors
}
// Repository Interface
public interface EmployeeRepository {
    Employee findEmployeeById(Long id);
}
// Service layer
public class EmployeeService {
    private EmployeeRepository repository;
    public EmployeeService(EmployeeRepository repository) {
        this.repository = repository;
    }
    public Employee getEmployeeDetails(Long id) {
        return repository.findEmployeeById(id);
    }
}
// Test class
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.*;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;
@ExtendWith(MockitoExtension.class)
public class EmployeeServiceTest {
    @Mock
    private EmployeeRepository repository;
    @InjectMocks
    private EmployeeService service;
    @Spy
    private Employee employeeSpy = new Employee();
    @Captor
    private ArgumentCaptor<Long> captor;
    @Test
    public void testGetEmployeeDetails() {
        Employee emp = new Employee();
        emp.setId(1L);
        emp.setName("John Doe");
        when(repository.findEmployeeById(1L)).thenReturn(emp);
        Employee result = service.getEmployeeDetails(1L);
        verify(repository).findEmployeeById(captor.capture());
        assertEquals(emp, result);
        assertEquals(1L, captor.getValue());
    }
}

Output:

The test testGetEmployeeDetails will pass, showing that the service retrieves the employee details and the captor captures the correct argument.

Code Explanation:

1. @Mock: Used to create a mock for the EmployeeRepository which is used to mock its behavior.

2. @InjectMocks: Creates an instance of EmployeeService and injects the mock EmployeeRepository into it.

3. @Spy: Used to spy on a real Employee object. Though it's not utilized in the current test, it's often used to stub specific methods and not the entire object.

4. @Captor: Captures the arguments passed to a method, so we can inspect them. Here, we captured the ID passed to the repository method.

5. @ExtendWith(MockitoExtension.class): Ensures Mockito initializes the mock and spy objects before any tests run.

5. Conclusion

Mockito annotations offer an effective way to create and manage mock objects for unit tests. By understanding and leveraging these annotations, you can write cleaner and more concise unit tests, ensuring the quality of your software components.

Comments