Mockito annotations create and wire test doubles such as mocks, spies and argument captors in a test class, so we do not call Mockito methods in every test. Mockito provides the annotations @Mock, @Spy, @Captor and @InjectMocks for this. We use them in unit tests to isolate a class from its dependencies and to verify the calls made to those dependencies. The following example creates a mock of ItemRepository and injects it into ItemService.
@ExtendWith(MockitoExtension.class)
public class ItemServiceTest {
@Mock
private ItemRepository itemRepository;
@InjectMocks
private ItemService itemService; // Assuming ItemService uses ItemRepository
@Test
public void testCreateItem() {
// ...
}
}
See Also: Spring Boot @MockBean Annotation
1. Initializing Mockito Annotations
Mockito does not process these annotations on its own. The test class must initialize them with the JUnit 5 extension, the JUnit 4 runner or rule, or the method MockitoAnnotations.openMocks().
1.1. With JUnit 5 / Spring Boot
To process Mockito annotations with JUnit 5, we register the extension class MockitoExtension with @ExtendWith.
@ExtendWith(MockitoExtension.class)
public class ApplicationTest {
// Annotated mocks and spies will be automatically initialized
}
Spring Boot 3 also uses JUnit 5 in its test framework, so the same extension works in Spring Boot testing.
1.2. With JUnit 4
JUnit 4 tests use either the runner class MockitoJUnitRunner or the rule class MockitoRule.
@RunWith(MockitoJUnitRunner.class)
public class MyTest {
// Annotated mocks and spies will be automatically initialized
// We can directly use them in the test methods
}
@ExtendWith(MockitoExtension.class)
public class MyTest {
// Annotated mocks and spies will be automatically initialized
// We can directly use them in the test methods
@Test
public void testSomething() {
// test code
}
}
1.3. Using MockitoAnnotations.openMocks()
Alternatively, the setup method of the test class calls MockitoAnnotations.openMocks(), which initializes the annotated mocks and spies in that class.
The previously used initMocks() method is now deprecated.
@BeforeEach
public void setup() {
MockitoAnnotations.openMocks(this);
}
2. Mockito @Mock
A mock is a test double that replaces a real dependency, returns default values from its methods and records every call. The annotation @Mock asks Mockito to create a mock of the field type, so the test does not create a real object.
The annotation @Mock is an alternative to the method Mockito.mock(classToMock), and both create the same mock. The annotation keeps the test class shorter, because the test does not repeat the same creation statement.
@Mock
HashMap<String, Integer> mockedMap;
//or
HashMap mockedMap = Mockito.mock(HashMap.class);
The annotation @Mock has the following advantages.
- It creates the objects required for a test in one line.
- It removes repetitive mock creation code.
- It makes the test class more readable.
- It makes a verification error easier to read, because the field name identifies the mock.
The following example mocks the class HashMap. In real tests, we mock application classes instead. The test puts a key-value pair in the mocked Map and verifies that the method invocation reached the mock. The mock does not store the pair, so size() returns 0.
@Mock
HashMap<String, Integer> mockHashMap;
@Test
public void saveTest() {
mockHashMap.put("A", 1);
Mockito.verify(mockHashMap, times(1)).put("A", 1);
Mockito.verify(mockHashMap, times(0)).get("A");
assertEquals(0, mockHashMap.size());
}
3. Mockito @Spy
A spy is a test double that wraps a real object, calls its real methods and records every interaction, as a mock does. The annotation @Spy creates a spy of the field type.
The following example uses a spied HashMap. The test adds one key-value pair, so size() returns 1, and get() returns the value added with the key. A mocked instance does not keep the pair.
@Spy
HashMap<String, Integer> hashMap;
@Test
public void saveTest()
{
hashMap.put("A", 10);
Mockito.verify(hashMap, times(1)).put("A", 10);
Mockito.verify(hashMap, times(0)).get("A");
assertEquals(1, hashMap.size());
assertEquals(new Integer(10), (Integer) hashMap.get("A"));
}
4. Mockito @Captor
An argument captor records the argument values passed to a method, so the test can assert on them later. The annotation @Captor creates an ArgumentCaptor instance.
Mockito verifies argument values with the equals() method of the argument class.
@Mock
HashMap<String, Integer> hashMap;
@Captor
ArgumentCaptor<String> keyCaptor;
@Captor
ArgumentCaptor<Integer> valueCaptor;
@Test
public void saveTest()
{
hashMap.put("A", 10);
Mockito.verify(hashMap).put(keyCaptor.capture(), valueCaptor.capture());
assertEquals("A", keyCaptor.getValue());
assertEquals(new Integer(10), valueCaptor.getValue());
}
5. @InjectMocks
The class under test needs its dependencies to run. The annotation @InjectMocks creates an instance of the class under test and inserts the mocks into it.
The annotation @InjectMocks marks the field that receives the injection. Mockito tries constructor injection first, then setter injection, then property injection, and injects only mocks.
@Mock
private ItemRepository itemRepository;
@InjectMocks
private ItemService itemService; // Assuming ItemService uses ItemRepository
If an injection strategy fails, Mockito does not report a failure.
Read more in Difference between @Mock and @InitMocks annotations.
6. Difference between @Mock and @Spy
With @Mock, Mockito creates an empty instance of the field type that records every interaction. The instance is not a real object, so it does not keep state changes.
With @Spy, Mockito wraps a real instance of the class and records every interaction. The instance keeps state changes.
7. Conclusion
Mockito annotations create and inject test doubles in JUnit tests. The annotation @Mock creates mocks, @Spy wraps real instances, @Captor captures argument values for assertions, and @InjectMocks injects the mocks into the class under test.
Happy Learning !!
If we want to test a method A of a given class and that method A is also calling another method B of the same class. How should this be tested?
If the first method is m1, and second method is m2, you can try this template:
@Testpublic void testA() {
MyService myService = new MyService();
MyService spyService = Mockito.spy(myService);
// Mock the behavior of method B
when(spyService.m2()).thenReturn("SomeValue");
String result = spyService.m1();
assertEquals("SomeValue", result);
// Verify that method m2 was called
verify(spyService).m2(); // Verify that m2() was invoked once
}
Hi,
I need to know, how I can inject real object with mocked object to a service in test case. Is it possible to do so?
You can use @Spy annotation use real object with mocked