Mockito Mock Vs. Spy: Differences & The Right Approach

Understand the differences between Mockito Mock and Spy, their use cases, and the right approach for effective unit testing.

Get Started free
Mockito Mock Vs. Spy Differences & The Right Approach
Home Guide Mockito Mock Vs. Spy: Differences & The Right Approach

Mockito Mock Vs. Spy: Differences & The Right Approach

In unit testing, mocking and spying are two important techniques for isolating a class or component’s behavior. Both are part of the Mockito framework, a widely used Java library for creating mock objects and performing unit tests.

Mocking allows the user to create a simulated object that copies the behavior of a real one but is entirely controlled by the user in the test. Spying allows wrapping an actual object to mock specific methods or behaviors while still allowing the real object to function for other methods.

Read this article to learn more about Mockito Mock and Spy, including their differences, use, and working patterns.

Mockito Mock vs Spy: Key Differences

Here are some of the major differences between Mockito Mock and Spy:

AspectMockito MockMockito Spy
DefinitionCreates a mock object of a class, which does not have real behavior unless explicitly defined.Wraps an existing object, allowing both real and mocked behavior.
BehaviorAnalyzes the behavior of a class. All methods return default values unless specified.Executes real methods unless explicitly mocked.
Use CaseIdeal for isolating tests by managing dependencies.Ideal for testing partial behaviors where some methods are real, and others are mocked.
StubbingAlways need explicit stubbing for method behavior.Allows partial stubbing along with real method calls.
Object TypeCan mock both interfaces and concrete classes.Can spy on both interfaces and concrete classes.
Default BehaviorReturns default values like null, 0, or false unless specified.Executes the real method unless explicitly mocked.
Created byCreated using Mockito.mock(Class<T>.class).Created using Mockito.spy(Object).

What is Mockito Mock?

A Mockito Mock is an object created by the Mockito framework that analyzes the behavior of a real object or class. By using mocks, any user can control what methods return and verify interactions with these methods, isolating unit tests from external dependencies.

Syntax and Real-World Example

Here’s an example of how to mock an object using Mockito:

import static org.mockito.Mockito.*;

public class UserServiceTest {




@Test

public void testGetUser() {

     // Create a mock of the UserRepository class

     UserRepository userRepository = mock(UserRepository.class);

     

         when(userRepository.getUserById(1)).thenReturn(new User(1, "Ayush Singh"));

   

     UserService userService = new UserService(userRepository);

     User user = userService.getUser(1);

   

     assertEquals("Ayush Singh", user.getName());

}

}
Copied

Importance of Mockito Mock

Below are the reasons why Mocking is important:

  • Isolation: Mocks help isolate the tested unit by replacing real dependencies with controlled mock objects.
  • Behavior control: Mocks allow the specification of exact behavior, such as method return values, exceptions, or interactions.
  • Test speed: Mocks speed up unit tests since they do not involve expensive operations, like database calls or HTTP requests.

How does Mockito Mock work?

Mockito mocks a class or interface by creating a fake version that a user can control. When a method is called on a mock object, it returns default values unless explicitly told to return something else using when(…).thenReturn(…).

How to Use Mock – Steps

Step 1: Create the mock object by using Mockito.mock(Class<T>.class).

Step 2: Use when(…).thenReturn(…) to specify what the mock should return.

Step 3: Call methods on the mock object in the test.

Step 4: Use verify(mock).methodCall() to confirm that methods were invoked.

What is Mockito Spy?

A Mockito Spy allows the user to wrap an existing object (real object) to spy on its behavior. It lets users mock certain methods while leaving the real methods untouched.

This is useful when users want to test real behavior but still mock certain methods or interactions.

Syntax and Real-World Example

Here’s the basic syntax along with an example to create a spy in Mockito:

import static org.mockito.Mockito.*;

public class UserServiceTest {

@Test

public void testSaveUser() {

       UserRepository realUserRepository = new UserRepository();

   

     UserRepository spyRepository = spy(realUserRepository);

     doReturn(false).when(spyRepository).save(any(User.class));

     

     // Test the method

     UserService userService = new UserService(spyRepository);

     boolean result = userService.saveUser(new User(1, "Ayush Singh"));




     assertFalse(result);

           }

}
Copied

Importance of Mockito Spy

Here are the reasons why Mockito Spy is important:

  • Partial mocking: Spy allows users to mock specific methods while keeping the real behavior of others.
  • Verification of real interactions: Spying is ideal when any user wants to verify real method calls in an object, especially when those methods are part of a larger, more complex operation.

How does Spy work?

Mockito spies on an existing object, allowing the real method to be executed unless explicitly mocked.

Unlike mocks, spies don’t automatically return default values; they pass on to the real method unless told otherwise.

How to Use Mockito Spy

Below are the steps on how you can start using Mockito Spy:

Step 1: Create the real object on which spy needs to be implemented.

Step 2: Use Mockito.spy() to wrap the real object.

Step 3: Use doReturn(…).when(…) to mock specific methods.

Step 4: Use verify(spy).methodCall() to verify interactions.

What is the difference between Spy and Mock?

Here is an explanation of the difference between Mockito Spy and Mockito Mock with the use of an example.

Example:

import static org.mockito.Mockito.*;

public class ServiceTest {

@Test

public void testSpyVsMock() {

     // Using Mock

     List<String> mockList = mock(List.class);

     when(mockList.size()).thenReturn(5);

     assertEquals(5, mockList.size());




     // Using Spy

     List<String> realList = new ArrayList<>();

     List<String> spyList = spy(realList);

     when(spyList.size()).thenReturn(5);

     assertEquals(5, spyList.size());




     spyList.add("Item");

     verify(spyList).add("Item");

        }

}
Copied

Output:

  • The mock object will return 5 for the size() method regardless of the actual data in the list.
  • The spy object will return the mocked value 5, but a user can verify real interactions, like adding () to the list.

Test on Real Devices

Mockito Mock vs Spy: How to choose?

Mockito provides Mock and Spy to help isolate dependencies in unit testing, but choosing the right approach depends on the testing scenario.

While Mock replaces the entire object with a dummy implementation, Spy allows partial mocking, letting some real methods execute.

Here’s how to decide which one to use:

When to Use Mock:

  • Ideal for isolating the unit under test without executing real code.
  • Useful when the object has external dependencies (e.g., database calls, API requests).
  • Best suited for testing interactions rather than actual method execution.

When to Use Spy:

  • Allows testing real behavior while mocking specific methods.
  • Useful when only certain methods need to be overridden, while others retain their actual implementation.
  • Helps verify interactions, such as tracking calls to real methods like add().

Common Challenges of Using Mockito Mock

Below is a list of some common limitations of using Mockito Mock:

  • Complex mocks: Creating mocks for classes with simple behavior can be difficult.
  • Overuse of mocks: Too many mocks can lead to flexible tests that are majorly connected to the implementation.
  • Stubbing difficulties: Mocks may need extensive setup to specify all method return values.

Best Practices of Using Mockito Mock

Here are some key best practices of using Mockit Mock:

  • Keep mocks simple and avoid unnecessary complexity.
  • Use mocks mainly to isolate the system under test from external dependencies.
  • Focus on verifying interactions with mocks to ensure methods are called as expected.

Common Challenges of Using Mockito Spy

Here are some common challenges of using Mockito Spy:

  • Real method execution: Spy executes real methods by default, which may cause unintended side effects.
  • Limited mocking: Unlike mocks, spies require explicit stubbing to override real method behavior.
  • Increased test complexity: Partial mocking can make tests harder to maintain and understand, leading to confusion.
  • Potential performance issues: Since real methods are executed, tests may run slower than pure mocks.

BrowserStack Automate Banner

Best Practices of Using Mockito Spy

Below are some best practices of using Mockito Spy:

  • Use spy selectively for cases where partial mocking is necessary.
  • Avoid unnecessary spying to prevent unintended real-method executions that may cause side effects.
  • Stub only required methods to maintain test reliability and avoid executing logic that isn’t needed for the test.
  • Combine with verification to ensure expected interactions with both real and mocked methods.

Talk to an Expert

Conclusion

Both techniques serve different purposes, with Mocks providing complete isolation of the unit under test and Spies allowing partial mocking while still retaining real behavior.

When choosing between Mock and Spy, it’s important to evaluate the complexity of the test, the behavior to isolate, and the interactions to verify.

Tools like BrowserStack Automate are mainly used for real-world testing environments. They allow the user to run the tests on real devices, ensuring that the app behaves as expected across different platforms and browsers. This provides an easy way to confirm that the code works well beyond local tests and mocks.

Tags
Automation Testing Real Device Cloud