During unit testing with junit and mockito, we use @Mock and @InjectMocks annotations to create objects and dependencies to be tested. Learn the difference between @Mock and @InjectMocks annotations in mockito.
1. Difference between Mock vs Stub Object
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 an interface to hide a dependency with cannot be tested in test environment e.g. database, network locations etc. A method invoked using mocked reference does not execute method body defined in class file, rather the method behavior is configured using when-thenReturn methods combinations.
In a junit test, we create objects for the class which needs to be tested and it’s methods to be invoked. We create mocks for the dependencies which will not be present in 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 class objects.
@Mock – creates mocks
@InjectMocks – creates objects and inject mocked dependencies
- Use @InjectMocks to create class instances which needs to be tested in test class.
- Use @InjectMocks when actual method body needs to be executed for a given class.
- Use @InjectMocks when we need all internal dependencies initialized with mock objects to work method correctly.
- Use @Mock to create mocks which are needed to support testing of class to be tested.
- Annotated class (to be tested) dependencies with @Mock annotation.
- We must define the when-thenRetrun methods for mock objects which class methods will be invoking during actual test execution.
3. @Mock and @InjectMocks Example
Let’s understand the difference between @Mock and @InjectMocks with an example. In this example, we have class MainClass
which 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. Java classes
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. Junit test for MainClass
Let’s write 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.initMocks(this); } @Test public void validateTest() { boolean saved = mainClass.save("temp.txt"); assertEquals(true, saved); } }
The test is executed successfully and we get below statements printed in console. Watch the console output very carefully.
Saved in database in Main class Saved in network in Main class
In above test, statements are printed which are written in MainClass.save() method, but not for dependent classes. It proves that method body was executed for only MainClass’s save() method because we created the actual object of MainClass using @InjectMocks
annotation. For dependent classes, we used mocks.
3.3. Verify method invocations on mocks
To verify that mock methods has been invoked, we must use mockito provided utility method verify(). It helps in verifying that mock methods has been executed while executing the actual test class method.
@Test public void validateTest() { boolean saved = mainClass.save("temp.txt"); assertEquals(true, saved); verify(dependentClassOne, times(1)).save("temp.txt"); verify(dependentClassTwo, times(1)).save("temp.txt"); }
4. Conclusion
In this mockito tutorial, we learned the difference between @Mock and @InjectMocks annotations. We learned what happen when we apply these annotation to classes in junit tests.
Happy Learning !!
References: Mockito Guide
Rakesh
It is Injectmock not initmock.
Jason
Not when you use the MockitoAnnotations.initMocks method.