How to Use Spy in Mockito with JUnit for Effective Testing
In JUnit tests, use
Mockito.spy() to create a spy object that wraps a real instance, allowing you to call real methods while still verifying interactions or stubbing specific methods. This helps test partial behavior without fully mocking the object.Syntax
The spy method in Mockito creates a spy object from a real instance. You can then stub or verify methods on this spy.
spyObject = Mockito.spy(realObject);- creates a spy wrapping the real object.Mockito.doReturn(value).when(spyObject).method();- stubs a method on the spy.Mockito.verify(spyObject).method();- verifies method calls on the spy.
java
MyClass realObject = new MyClass(); MyClass spyObject = Mockito.spy(realObject); Mockito.doReturn("stubbed").when(spyObject).someMethod(); spyObject.someMethod(); Mockito.verify(spyObject).someMethod();
Example
This example shows how to spy on a list, stub one method, and verify method calls using JUnit and Mockito.
java
import static org.mockito.Mockito.*; import static org.junit.jupiter.api.Assertions.*; import java.util.ArrayList; import java.util.List; import org.junit.jupiter.api.Test; public class SpyExampleTest { @Test public void testSpyList() { List<String> realList = new ArrayList<>(); List<String> spyList = spy(realList); // Stub size() method to return 100 doReturn(100).when(spyList).size(); // Add elements calls real methods spyList.add("one"); spyList.add("two"); // size() returns stubbed value assertEquals(100, spyList.size()); // Verify add was called twice verify(spyList).add("one"); verify(spyList).add("two"); } }
Output
Test passed successfully with all assertions and verifications met.
Common Pitfalls
- Calling real methods unintentionally: Spy calls real methods by default, so side effects can happen if not careful.
- Stubbing with
when(spy.method()): This can call the real method and cause issues; usedoReturn().when(spy)instead. - Spying on null or final classes: Mockito cannot spy on null objects or final classes without additional configuration.
java
/* Wrong way - calls real method during stubbing, may cause side effects */ // when(spyList.size()).thenReturn(100); /* Right way - avoids calling real method during stubbing */ doReturn(100).when(spyList).size();
Quick Reference
Use this cheat sheet to remember key points about spy in Mockito:
| Action | Syntax | Notes |
|---|---|---|
| Create spy | MyClass spy = Mockito.spy(realObject); | Wraps real object, calls real methods by default |
| Stub method | Mockito.doReturn(value).when(spy).method(); | Avoids calling real method during stubbing |
| Verify call | Mockito.verify(spy).method(); | Checks if method was called on spy |
| Avoid | Mockito.when(spy.method()).thenReturn(value); | May call real method, causing side effects |
Key Takeaways
Use Mockito.spy() to wrap real objects for partial mocking in JUnit tests.
Always stub spy methods with doReturn().when() to avoid calling real methods during stubbing.
Verify interactions on spy objects with Mockito.verify() as usual.
Be cautious of side effects since spies call real methods by default.
Mockito cannot spy on null or final objects without extra setup.