During unit testing with junit and mockito, generally, we use @Mock and @InjectMocks annotations to create mocks and SUT (System Under Test) to be tested. In this tutorial, we will learn the difference between @Mock and @InjectMocks annotations in mockito.
1. What is a Mock?
It is important to understand the difference between a mock and an object. An object is an actual instance of a class and any method invoked using object reference will execute the method body defined in the class file.
A mock object is a proxy interface to hide an underlying dependency with cannot be tested in a test environment e.g. database, network locations etc. A method invoked using mocked reference does not execute the actual method body defined in the class file, rather the method behavior is configured using when(...).thenReturn(...)
methods.
- In a junit test, we create objects for the class which need to be tested and its methods to be invoked.
- We create mocks for the dependencies which will not be present in the test environment and objects are dependent on it to complete the method call.
2. Difference between @Mock and @InjectMocks
In mockito-based junit tests, @Mock annotation creates mocks and @InjectMocks creates actual objects and injects mocked dependencies into it.
- Use @InjectMocks to create class instances that need to be tested in the test class. We call it ‘code under test‘ or ‘system under test‘.
- Use @InjectMocks when actual method body needs to be executed for a given class.
- Use @InjectMocks when we need all or few internal dependencies initialized with mock objects to work method correctly.
- Use @Mock to create mocks that are needed to support the testing of SUT.
- We must define the
when(...).thenReturn(...)
methods for mock objects whose class methods will be invoked during actual test execution.
3. Demo
Let’s understand the difference between @Mock and @InjectMocks with an example. In this example, we have a class MainClass that has a method save().
MainClass
has a dependency on DatabaseDAO
and NetworkDAO
. When we call MainClass.save()
method, it internally calls save methods of both dependent objects.
3.1. System Under Test
public class MainClass {
DatabaseDAO database;
NetworkDAO network;
//Setters and getters
public boolean save(String fileName)
{
database.save(fileName);
System.out.println("Saved in database in Main class");
network.save(fileName);
System.out.println("Saved in network in Main class");
return true;
}
}
public class DatabaseDAO {
public void save(String fileName) {
System.out.println("Saved in database");
}
}
public class NetworkDAO {
public void save(String fileName) {
System.out.println("Saved in network location");
}
}
3.2. Unit Test
Let’s write the junit test for MainClass.
import static org.junit.Assert.assertEquals;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
public class ApplicationTest
{
@InjectMocks
MainClass mainClass;
@Mock
DatabaseDAO dependentClassOne;
@Mock
NetworkDAO dependentClassTwo;
@Before
public void init() {
MockitoAnnotations.openMocks(this);
}
@Test
public void validateTest()
{
//record expectations with mock methods
when(dependentClassOne.save()).thenReturn(true);
when(dependentClassTwo.save()).thenReturn(true);
boolean saved = mainClass.save("temp.txt");
assertEquals(true, saved);
//verify recorded expectations
}
}
4. Conclusion
In this mockito tutorial, we learned the difference between @Mock and @InjectMocks annotations. We learned what happens when we apply these annotations to classes in junit tests.
Happy Learning !!
It is Injectmock not initmock.
Not when you use the MockitoAnnotations.initMocks method.