Translated from reprinted howtodoinjava.com/mockito/moc…

This Mockito tutorial article will help you learn more about Mockito annotations such as @mock, @Spy, @Captor, and @InjectMocks to write better unit tests.

1. Mockito annotation

1.1. @ the Mock

The @mock annotation is often used to create and inject Mock instances. We will use the Mockito framework to create a mock instance class instead of actually creating the required object.

Mock annotations can also be used as a function assignment var somethingYouWantMock = mockito. Mock (classToMock). They have the same effect, while @mock annotations usually make the code look “cleaner”. Because we don’t want to have a bunch of mockito. mock functions repeated all over the code.

Advantages of @mock annotations:

  • Ability to quickly create objects for testing
  • Duplicate simulation creation code is minimal
  • The test class is more readable
  • Validation errors are easier to read because the annotation’s mock class is directly a property of the class and can be given meaning by field names.

In the example given below, we simulate the HashMap class. In the real test, we will simulate the real application class. We put a key-value pair in the map and verify that the method call is executed on the simulated Map instance.

@Mock
HashMap<String, Integer> mockHashMap;
 
@Test
public void saveTest(a)
{
    mockHashMap.put("A".1);
     
    Mockito.verify(mockHashMap, times(1)).put("A".1);
    Mockito.verify(mockHashMap, times(0)).get("A");
 
    assertEquals(0, mockHashMap.size());
}
Copy the code

To mock is to make a mock object that does not call the methods of the real object. All the behavior of the mock object is undefined and its properties have no values. You have to define the behavior of the mock object. For example, you can mock a fake size() that returns 100 without actually creating a Map of size 100.)

. when(mockHashMap.size()) .thenReturn(100);
    
    assertEquals(100, mockHashMap.size()); .Copy the code

1.2. @ Spy

The @spy annotation is used to create and monitor a real object. The @Spy object can call all the normal methods of the monitored object while still tracking every interaction, and just like with mocks, you can define your own behavior.

As you can see, in the example given below, size becomes 1 because we added a key-value pair to it. We can also actually get value by key. This is not possible in the Mock annotation example.

Because a mock simulates the entire generation of a fake object, a spy is like a spy lurking inside a real object to tamper with the behavior.

@Spy
HashMap<String, Integer> hashMap;
 
@Test
public void saveTest(a)
{
    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"));
}
Copy the code

Difference between @mock and @spy

When using @Mock, Mockito creates an instance of the base shell of a class that is solely used to track all interactions with it. This is not a real object and does not maintain state and does not change.

When using @Spy, Mockito creates a real instance of a class that tracks every interaction with it, and this real class maintains changes in class state.

1.3 @ Captor

The @captor annotation is used to create ArgumentCaptor instances that capture method parameter values for further assertion validation.

Note that Mockito uses the equals() method of the argument class to verify that the parameters are the same.

@Mock
HashMap<String, Integer> hashMap;
 
@Captor
ArgumentCaptor<String> keyCaptor;
 
@Captor
ArgumentCaptor<Integer> valueCaptor;
 
@Test
public void saveTest(a) 
{
    hashMap.put("A".10);
 
    Mockito.verify(hashMap).put(keyCaptor.capture(), valueCaptor.capture());
 
    assertEquals("A", keyCaptor.getValue());
    assertEquals(new Integer(10), valueCaptor.getValue());
}
Copy the code

1.4 @ InjectMocks

In Mockito, we need to create the class object being tested and then mock in its dependencies to fully test the behavior. Therefore, we use the @injectMocks annotation.

InjectMocks marks a field that should be injected. Mockito will try to inject your mock identity through constructor injection, setter injection, or property injection according to the following priorities. Mockito does not report an error if the injection of any of the three given injection strategies above fails.

More information: The difference between Mock and @initMock annotations

@injectMocks is usually the class you want to test, and it will automatically inject the mock property of the class you want to test into it. @mock is the class you want to Mock.