Mockito @Spy Example

1. Introduction

The Mockito framework introduces the @Spy annotation to create a spy (or partial mock) of an object. While typical mocks created using @Mock will have all their methods stubbed to do nothing by default (unless they're explicitly stubbed), a spy uses the real method implementations of the spied object. However, you can still override some of its behavior (i.e., stub specific methods) when needed. This is particularly useful when you want to test the real code of a class but override the behavior of certain methods without calling the actual implementations.

2. Example Steps

1. Define a class with some methods.

2. Create a test class.

3. Within the test class, create a spy of the original class using @Spy.

4. Invoke the methods of the spied object in tests.

5. Stub specific methods of the spy and verify interactions.

3. Mockito @Spy Example

import org.junit.jupiter.api.Test;
import org.mockito.Spy;
import org.mockito.MockitoAnnotations;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;

class MathService {
    public int add(int a, int b) {
        return a + b;
    }

    public int multiply(int a, int b) {
        return a * b;
    }
}

public class MathServiceTest {
    // Create a spy of MathService
    @Spy
    MathService mathService;

    @Test
    public void testMultiply() {
        // Initializing the spy
        MockitoAnnotations.initMocks(this);

        // Call the real method of multiply
        int result = mathService.multiply(5, 4);
        assertEquals(20, result);

        // Stubbing the add method of the spy to return a fixed value
        doReturn(100).when(mathService).add(50, 50);
        int additionResult = mathService.add(50, 50);
        assertEquals(100, additionResult);

        // Verifying the interactions with the spy
        verify(mathService).multiply(5, 4);
        verify(mathService).add(50, 50);
    }
}

Output:

The test will pass. The multiply method returns the actual value of 20, while the add method, which was stubbed, returns the fixed value of 100.

4. Step By Step Explanation

1. We have a simple MathService class with methods to add and multiply.

2. In the MathServiceTest, we create a spy of the MathService class using the @Spy annotation.

3. We then initialize the spy with MockitoAnnotations.initMocks(this);.

4. The test testMultiply first calls the multiply method of the spied mathService. Since we haven't stubbed this method, it uses the real implementation and returns 20.

5. We then stub the add method of the spy to always return 100 when called with arguments 50 and 50. When we subsequently call this method with these arguments, it returns the stubbed value of 100 instead of the real sum.

6. Lastly, we verify that the methods multiply and add were called with the specified arguments.


Comments