We can use Mockito Spy to partial mock an object. When we spy on an object, the real methods are being called unless it’s stubbed.
Mockito Spy
We can create mockito spy objects using two ways.
- Mockito.spy() method
- Mockito @Spy Annotation
Mockito spy() Method Example
Below is a simple example of using Mockito spy()
method.
package com.journaldev.mockito.spy;
import static org.mockito.Mockito.*;
import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class MockitoSpyExample {
@Test
void test() {
List<String> list = new ArrayList<>();
List<String> spyOnList = spy(list);
spyOnList.add("A");
assertEquals(1, spyOnList.size());
assertEquals("A", spyOnList.get(0));
spyOnList.add("E");
assertEquals(2, spyOnList.size());
assertEquals("E", spyOnList.get(1));
when(spyOnList.size()).thenReturn(10);
assertEquals(10, spyOnList.size());
}
}
Notice that add()
, get()
and size()
methods real implementations are being called till they are not stubbed. At later point of time, we have stubbed size()
method. From that point onwards, stubbed method will be called.
Mockito @Spy Annotation Example
Here is an example of @Spy annotation, we have converted above test program to use @Spy annotation.
package com.journaldev.mockito.spy;
import static org.mockito.Mockito.*;
import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import static org.junit.jupiter.api.Assertions.*;
public class MockitoSpyAnnotationExample2 {
@Spy
List<String> spyOnList = new ArrayList<>();
@BeforeEach
public void setup() {
MockitoAnnotations.initMocks(this);
}
@Test
void test() {
spyOnList.add("A");
assertEquals(1, spyOnList.size());
assertEquals("A", spyOnList.get(0));
spyOnList.add("E");
assertEquals(2, spyOnList.size());
assertEquals("E", spyOnList.get(1));
when(spyOnList.size()).thenReturn(10);
assertEquals(10, spyOnList.size());
}
}
When we have to reuse spied object at multiple places, it’s better to use @Spy annotation.
Note that it’s not compulsory to create a spy object using another instance, below is also an acceptable usage.
List spyOnList = spy(List.class);
@Spy
List spyOnList1;
However, it’s recommended to provide the implementation. Because in this case, Mockito will try to instantiate the mock object using the no-args constructor. Also, it won’t instantiate inner classes, local classes etc. And we know that List implementation classes use inner classes. So you won’t get the expected results from your tests.
Mockito Spy vs doCallRealMethod()
We can also use doCallRealMethod() on a mock object to call the real method, however, it’s recommended to use Spy to create partial mocks. Because in Spy, we are instantiating an object, whereas when we create a mock object, Mockito creates a bare-minimum instance of the object. Chances are that the required dependencies are not initialized when mock is being created, leading to erroneous results.
void test() { in the first test does not work. After chaning it to public void testSpy() { it worked OK.