A spy object wraps a real object and allows you to verify method calls while still executing the actual methods. This helps in testing side effects and interactions.
import static org.mockito.Mockito.*; import org.junit.jupiter.api.Test; import java.util.ArrayList; import java.util.List; public class SpyTest { @Test public void testSpyList() { List<String> list = new ArrayList<>(); List<String> spyList = spy(list); spyList.add("one"); spyList.add("two"); verify(spyList).add("one"); verify(spyList).add("two"); assert(spyList.size() == 2); } }
The spy wraps the real list, so add() calls actually add elements. Verifications confirm the calls happened. The size is 2, so assertion passes.
import static org.mockito.Mockito.*; import org.junit.jupiter.api.Test; public class SpyCallCountTest { public static class Calculator { public int add(int a, int b) { return a + b; } } @Test public void testAddCallCount() { Calculator calc = spy(new Calculator()); calc.add(1, 2); calc.add(3, 4); calc.add(5, 6); // Which verify statement is correct? } }
The add method is called three times, so verify with times(3) is correct.
import static org.mockito.Mockito.*; import org.junit.jupiter.api.Test; public class SpyStubTest { public static class Service { public String getData() { return "real data"; } } @Test public void testStubSpy() { Service service = spy(new Service()); when(service.getData()).thenReturn(null); String result = service.getData(); assert(result == null); } }
When stubbing spy methods, using when() calls the real method immediately, which can cause errors. Using doReturn() avoids calling the real method.
Spies wrap real objects and allow real methods to run unless stubbed, making them useful to verify behavior and side effects in integration tests.
