Mockito Annotations: @Mock, @Spy, @InjectMocks and @Captor

Lokesh Gupta

In this tutorial, learn about Mockito annotations such as @Mock, @Spy, @Captor and @InjectMocks. Learn to write unit tests for behavior testing using mockito annotations.

@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

In order to bootstrap Mockito with the above annotations, the test class should initialize the annotation using one of the following given ways:

1.1. With JUnit 5 / Spring Boot

To process Mockito annotations with JUnit 5, we need to use MockitoExtention as follows:

@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 we can use this initialization technique in Spring Boot testing also.

1.2. With JUnit 4

For legacy JUnit 4, we can use either MockitoJUnitRunner or MockitoRule classes.

@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, we can programmatically bootstrap mockito using openMocks() method for initializing annotated mocks and spies in a test class.

The previously used initMocks() method is now deprecated.

@BeforeEach
public void setup() {

  MockitoAnnotations.openMocks(this);
}

2. Mockito @Mock

The @Mock annotation is used to create and inject mocked instances. We do not create real objects, rather ask mockito to create a mock for the class.

The @Mock annotation is an alternative to Mockito.mock(classToMock). They both achieve the same result. Using @Mock is usually considered “cleaner“, as we don’t fill up the tests with boilerplate assignments that all look the same.

@Mock
HashMap<String, Integer> mockedMap;

//or

HashMap mockedMap = Mockito.mock(HashMap.class);

Using the @Mock annotation –

  • allows shorthand creation of objects required for testing.
  • minimizes repetitive mock creation code.
  • makes the test class more readable.
  • makes the verification error easier to read because field name is used to identify the mock.

In the given example, we have mocked the HashMap class. In real tests, we shall be mocking actual application classes. We put a key-value pair in Map, and then verified that method invocation was performed on mocked map instance.

@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

The @Spy annotation is used to create a real object and spy on that real object. A spy helps to call all the normal methods of the object while still tracking every interaction, just as we would with a mock.

Notice in the given example, how the size of the Map is maintained to 1 because we added one key-value pair to it. We are also able to get back the value added to Map using its key. It is not possible in mocked instances.

@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

The @Captor annotation is used to create an ArgumentCaptor instance which is used to capture method argument values for further assertions.

Note that mockito verifies argument values using the equals() method of 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

In mockito, we need to create the object of a test class to be tested and then insert the mocked dependencies to test the behavior completely. To do this, we use @InjectMocks annotation.

The @InjectMocks marks a field on which injection should be performed. Mockito will try to inject mocks only either by constructor injection, setter injection, or property injection – in this order.

@Mock
private ItemRepository itemRepository;

@InjectMocks
private ItemService itemService; // Assuming ItemService uses ItemRepository

If any of the given injection strategies fail, then Mockito won’t report failure.

Read More : Difference between @Mock and @InitMocks annotations

6. Difference between @Mock and @Spy

When using @Mock, mockito creates a bare-bones shell instance of the field type, entirely instrumented to track interactions with it. This is not a real object and does not maintain the state changes to it.

When using @Spy, mockito proxies a real instance of the class and tracks every interaction with it. It maintains the state changes to it.

7. Conclusion

This Mockito tutorial discussed different ways to create and inject mocked objects in JUnit tests. It also discusses the spy of existing concrete instances using @Spy and argument matching with ArgumentCaptor.

Happy Learning !!

Comments

Subscribe
Notify of
guest
4 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.

Our Blogs

REST API Tutorial

Dark Mode

Dark Mode