In Java, a spy is an object that is partially mocked. Unlike a regular mock, which creates a completely new instance of a class with all methods mocked, a spy maintains the original behavior of the object while allowing specific methods to be mocked.
Let's illustrate this with an example. Consider a simple Calculator
class:
public class Calculator {
public int add(int a, int b) {
return a + b;
}
public int subtract(int a, int b) {
return a - b;
}
}
Now, let's say we want to create a spy for this Calculator
class and mock the add
method while keeping the subtract
method intact. We can achieve this using Mockito's spy()
method.
import org.junit.jupiter.api.Test;
import static org.mockito.Mockito.*;
public class CalculatorTest {
@Test
public void testSpy() {
// Create a spy for the Calculator class
Calculator calculatorSpy = spy(new Calculator());
// Mock the add method of the spy
when(calculatorSpy.add(2, 3)).thenReturn(10); // Mocking add method
// Call the subtract method (real implementation)
int subtractResult = calculatorSpy.subtract(5, 3);
// Call the add method (mocked behavior)
int addResult = calculatorSpy.add(2, 3);
// Verify that the subtract method works as expected (real implementation)
assert(subtractResult == 2); // 5 - 3 = 2
// Verify that the add method is mocked
assert(addResult == 10); // Mocked result
}
}
In this example:
Calculator
class using spy(new Calculator())
.add
method of the spy using when(calculatorSpy.add(2, 3)).thenReturn(10)
.subtract
method of the spy, which invokes the real implementation of the subtract
method.add
method of the spy, which invokes the mocked behavior we defined earlier.Using a spy allows you to selectively mock methods of an object while still using its real implementation for other methods.