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
Feature | Mock | Spy |
Default behavior | Returns default values | Retains real behavior |
Method stubbing | Required for any meaningful value | Optional and selective |
Used for | Fully simulated behavior | Partial 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.