Mockito Spy – Partial Mock

Filed Under: Mockito

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.

  1. Mockito.spy() method
  2. 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.

You can look at more Mockito examples from our GitHub Repository.

Leave a Reply

Your email address will not be published. Required fields are marked *

close
Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages