Mockito
Spy
Mock
Java
Unit Testing

Mockito - Spy vs Mock

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Mockito is a popular Java-based mocking framework used for unit testing by creating mock objects. Understanding the distinction between different Mockito annotations like @Mock and @Spy is crucial for effective testing and ensuring clean code. In this article, we will delve into the differences, use cases, and examples associated with these annotations.


Overview of Mockito

Mockito simplifies the testing of Java applications by allowing developers to create mock objects for the components that are out of scope for the unit test. Using mock objects can drastically reduce the complexity of the test setup, as external dependencies can be easily managed or altered to suit the needs of a test case.


@Mock vs @Spy

Both @Mock and @Spy serve distinct purposes within the Mockito framework. Here is a technical differentiation between the two:

  • @Mock: This annotation is used to create a mock object of a class or interface. When the object is mocked, all of its methods are stubbed to return default values. You can specify behavior using Mockito.when() and configure the mock object as desired.
  • @Spy: This annotation indicates that the object is a partial mock or spy. Unlike @Mock, the object retains its original behavior unless a method is explicitly stubbed. @Spy allows calling real methods unless explicitly mocked.

Key Differences

Feature/Aspect@Mock@Spy
Object behaviorMocks all methods within the object to return default values unless specified manually.Calls real methods unless they are specifically stubbed.
Use caseIdeal when the entire behavior of the dependency needs to be abstracted or simulated.Useful when testing particular methods while relying on the actual behavior of others.
Interaction verificationFocuses more on setting expected interactions between the test subject and its dependencies.Important for verifying real interactions and assessing partial behavior changes.
Implementation NaturePure mock object without any underlying instance of the class.Creates a spy object that is a wrapper around the actual object instance.

Technical Examples

Using @Mock

java
1import static org.mockito.Mockito.*;
2import org.mockito.Mock;
3import org.mockito.MockitoAnnotations;
4
5public class ExampleServiceTest {
6
7    @Mock
8    private ExampleRepository exampleRepository;
9
10    private ExampleService exampleService;
11
12    @Before
13    public void init() {
14        MockitoAnnotations.openMocks(this);
15        exampleService = new ExampleService(exampleRepository);
16    }
17
18    @Test
19    public void testExampleMethod() {
20        when(exampleRepository.getData()).thenReturn("Mock Data");
21        String result = exampleService.getProcessedData();
22        assertEquals("Mock Data", result);
23        verify(exampleRepository).getData();
24    }
25}

Using @Spy

java
1import org.mockito.Spy;
2import org.mockito.MockitoAnnotations;
3
4public class AnotherServiceTest {
5
6    @Spy
7    private ExampleService exampleService;
8
9    @Before
10    public void init() {
11        MockitoAnnotations.openMocks(this);
12    }
13
14    @Test
15    public void testExampleSpyMethod() {
16        doReturn("Spied Data").when(exampleService).getData();
17        String result = exampleService.getProcessedData();
18        assertEquals("Processed Spied Data", result); // Assuming process prefixes the data
19    }
20}

Advanced Features: Mixing @Mock and @Spy

In complex scenarios, you might decide to combine @Mock and @Spy. For instance, you might mock a data repository but still spy on the service to verify certain aspects of its behavior without altering its business logic significantly.

java
1@Mock
2private ExampleRepository exampleRepository;
3
4@Spy
5private ExampleService exampleServiceWithSpy;

Here, the exampleRepository is fully mocked, while the exampleServiceWithSpy uses the real service's logic but with controlled behavior of specific methods, if required.


Subtopics

Partial Mocks vs Full Mocks

Partial mocks, possible with @Spy, may be necessary when you want to test the functionality of a unit with partial replacement of its methods. This bypasses the limitation of traditional full mocks where you mock every method behavior.

Exception Testing

With both @Mock and @Spy, developers can test how their units handle exceptions. This is crucial for ensuring reliability and robustness in error handling.

java
// Example of exception handling
when(exampleRepository.getData()).thenThrow(new RuntimeException("Database Error"));

Conclusion

Choosing between @Mock and @Spy primarily depends on the test goals. While @Mock is widely used for simulating and abstracting away external interactions, @Spy provides a blend of real and mock behavior that is advantageous in scenarios requiring partial method stubbing.

Understanding when and how to use each effectively can significantly contribute to the robustness of unit testing suites, making the development cycle both efficient and reliable.


Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.