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.
{{ 'Comments (%count%)' | trans {count:count} }}
{{ 'Comments are closed.' | trans }}