When we should use @Mock and @InjectMocks annotations

December 13, 2020 No comments Mockito Java Library Mock InjectMocks

1. Introduction

This article will cover the differences between @Mock and @InjectMocks annotations from the Mockito testing framework. These two exists in a single unit test and allows to create a test object filled with mock classes ready for assertions.

2. Using @Mock annotation

The @Mock annotation marks a field as a mock - a dummy implementation of a real object on which we could define the specific behavior that will take a place after we call particular methods.

Let's consider the following example unit test that uses @Mock annotation to create a mock of a List:

package com.frontbackend.libraries.mockito;

import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.times;

import java.util.List;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class MockitoMockTest {

    @Mock
    private List<String> mock;

    @Test
    public void shouldAddItemsToList() {
        mock.add("one");
        mock.add("two");

        Mockito.verify(mock, times(2)).add(anyString());
        Mockito.verify(mock).add("one");
        Mockito.verify(mock).add("two");
    }
}

In this example, we created a mock object and then call the add(...) method on that object twice. Mockito.verify(...) was used to verify if that specific method was called two times, with given parameters.

You can see this unit test does not test any exceptional cases. That's why using just mock objects in unit tests doesn't make any sense. @Mock annotation should always exist in conjunction with @InjectMocks.

3. Using @InjectMocks annotation

The @InjectMocks annotation creates an instance of the class and injects all the necessary mocks, that are created with the @Mock annotations, to that instance.

The following sample code shows how @Mock and @InjectMocks works.

Consider we have a Car and a Driver class:

public class Car {

    private final Driver driver;

    public Car(Driver driver) {
        this.driver = driver;
    }

    public String printWelcome() {
        return String.format("Welcome %s!", driver.getName());
    }
}
public class Driver {

    private final String name;

    public Driver(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

As you see, the Car class needs theDriver object to printWelcome() message.

import com.frontbackend.libraries.mockito.model.Car;
import com.frontbackend.libraries.mockito.model.Driver;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;

import static org.junit.Assert.assertEquals;

@RunWith(MockitoJUnitRunner.class)
public class MockitoCarDriverTest {

    @Mock
    private Driver driver;

    @InjectMocks
    private Car car;

    @Test
    public void printWelcomeTest() {
        Mockito.when(driver.getName()).thenReturn("John");

        String msg = car.printWelcome();

        assertEquals("Welcome John!", msg);
    }
}

Mockito will mock a Driver class and configure its behavior using the when(...).thenReturn(...) notation. Using @InjectMocks Mockito will put that Driver into Car object.

Notice that we don't have to initiate the Car object. Mockito will do that for us.

4. Conclusion

In this article, we presented two annotations that come with the Mockito framework and are the most common ones. Note that you must use @RunWith(MockitoJUnitRunner.class) or Mockito.initMocks(this) to initialize these annotations. In JUnit 5 instead of @RunWith, you should use @ExtendWith(MockitoExtension.class). The @Mock and @InjectMocks exists in conjunction, almost every Mockito unit test will have that pair.

As usual, the code used in this tutorial is available under GitHub repository.

{{ message }}

{{ 'Comments are closed.' | trans }}