Learnitweb

Understanding Spies in Mockito

In this tutorial, we will learn about an important concept in Mockito testing called spying. Until now, you may have been working only with mocks. Spies behave differently from mocks in some critical ways. Let’s dive into it.

1. Introduction to Mocks

When you create a mock of a class using Mockito, all the methods of that class lose their original behavior. They return default values unless explicitly stubbed.

Example:

List<String> mockList = mock(ArrayList.class);

System.out.println(mockList.get(0)); // null
System.out.println(mockList.size()); // 0

mockList.add("Test");
System.out.println(mockList.size()); // still 0

when(mockList.size()).thenReturn(5);
System.out.println(mockList.size()); // 5

As seen above, adding elements to the mock has no effect unless you stub the methods manually. The class is essentially an empty shell.

2. Introduction to Spies

Spies, on the other hand, wrap real objects. They preserve the original behavior of the class and allow selective stubbing.

Creating a Spy:

List<String> spyList = spy(new ArrayList<>());

Example Behavior:

spyList.add("Test0");
System.out.println(spyList.get(0)); // "Test0"
System.out.println(spyList.size()); // 1

spyList.add("Test1");
spyList.add("Test2");
System.out.println(spyList.size()); // 3

when(spyList.size()).thenReturn(5);
System.out.println(spyList.size()); // 5

After the stubbing of size(), the real behavior is overridden, and it always returns 5 regardless of the actual content.

3. Difference Between Mock and Spy

FeatureMockSpy
Default behaviorReturns default valuesRetains real behavior
Method stubbingRequired for any meaningful valueOptional and selective
Used forFully simulated behaviorPartial mocking, real object watch

4. Exception with Spies

Calling methods on a spy that assume data presence can throw exceptions if the data is not present.

Example:

List<String> spyList = spy(new ArrayList<>());
System.out.println(spyList.get(0)); // Throws IndexOutOfBoundsException

To avoid this, ensure the necessary setup (like adding elements) is done before calling such methods.

5. Verifying Spy Interactions

You can use verify() on a spy just like a mock.

spyList.add("Test4");
verify(spyList).add("Test4"); // Verifies interaction

This helps monitor how the real object is used during tests.

6. When to Use Spies

Use spies when:

  • You want to use the actual object but still observe or stub selective behavior.
  • You want to avoid mocking everything and instead work with the real implementation.
  • You need to verify interaction or behavior within the real object.