Introduction
In this chapter, we will learn about the @Spy annotation in Mockito. This annotation is used to create spy objects, which are partial mocks of real objects. Spies allow you to call real methods while still being able to stub and verify certain behaviors.
Key Points about the @Spy Annotation
- Partial Mocks: The
@Spyannotation creates partial mocks that allow real methods to be called. - Real Method Invocation: Unlike mocks, spies call the actual methods unless they are stubbed.
- Used for Real Objects: Useful when you want to test the real behavior of an object but need to stub specific methods.
- Initialization: Requires initialization using
MockitoAnnotations.openMocks(this).
Setting Up Mockito for @Spy Annotation
Ensure that you have the necessary dependencies in your pom.xml if you are using Maven:
<dependencies>
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-core -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.2.0</version>
<scope>test</scope>
</dependency>
<!-- JUnit 5 dependency -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
</dependencies>
Example: Using @Spy Annotation
Description
In this example, we will create a Calculator class with basic arithmetic operations. We will use the @Spy annotation to create a spy of the Calculator class, allowing us to call real methods while stubbing some behaviors.
Class Under Test: Calculator
public class Calculator {
public int add(int a, int b) {
return a + b;
}
public int subtract(int a, int b) {
return a - b;
}
public int multiply(int a, int b) {
return a * b;
}
public int divide(int a, int b) {
if (b == 0) {
throw new IllegalArgumentException("Division by zero");
}
return a / b;
}
}
Test Class: CalculatorTest
import static org.mockito.Mockito.*;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Spy;
import org.mockito.MockitoAnnotations;
import static org.junit.jupiter.api.Assertions.*;
public class CalculatorTest {
@Spy
private Calculator calculator;
@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
}
@Test
void testAdd_RealMethod() {
// Act
int result = calculator.add(10, 20);
// Assert
assertEquals(30, result);
verify(calculator).add(10, 20);
}
@Test
void testSubtract_RealMethod() {
// Act
int result = calculator.subtract(20, 10);
// Assert
assertEquals(10, result);
verify(calculator).subtract(20, 10);
}
@Test
void testMultiply_StubbedMethod() {
// Arrange
doReturn(100).when(calculator).multiply(10, 10);
// Act
int result = calculator.multiply(10, 10);
// Assert
assertEquals(100, result);
verify(calculator).multiply(10, 10);
}
@Test
void testDivide_RealMethod() {
// Act
int result = calculator.divide(20, 4);
// Assert
assertEquals(5, result);
verify(calculator).divide(20, 4);
}
@Test
void testDivideByZero_RealMethod() {
// Act & Assert
assertThrows(IllegalArgumentException.class, () -> calculator.divide(10, 0));
verify(calculator).divide(10, 0);
}
}
Explanation
- Spy Annotation:
@Spy private Calculator calculator;The
@Spyannotation creates a spy object for theCalculatorclass. This allows real methods to be called while also enabling stubbing and verification. - Initializing Spies:
@BeforeEach void setUp() { MockitoAnnotations.openMocks(this); }The
MockitoAnnotations.openMocks(this)method initializes the spy objects. This is typically done in a@BeforeEachmethod to ensure spies are set up before each test. - Test Method:
@Test void testMultiply_StubbedMethod() { // Arrange doReturn(100).when(calculator).multiply(10, 10); // Act int result = calculator.multiply(10, 10); // Assert assertEquals(100, result); verify(calculator).multiply(10, 10); }This test method demonstrates stubbing a method in the spy. The real
multiplymethod is overridden to return100, and the result is verified.
Output

Conclusion
The @Spy annotation in Mockito is used for creating partial mocks. It allows you to call real methods while also enabling stubbing and verification of specific behaviors. In this section, we demonstrated how to use the @Spy annotation with a simple Calculator example. This approach helps you test the real behavior of objects while still having control over certain methods, making your tests more comprehensive and maintainable.