Mockito Spy vs Mock: Understanding the Differences
In the landscape of Java testing, the tools provided by Mockito have emerged as essential aids for creating effective and reliable unit tests. Among these tools, the concepts of spies and mocks stand out, offering developers different approaches to verification and interaction with objects.
Through comprehensive exploration, real-world examples, and comparisons, we’ll unravel the distinctions that set them apart. By the time you reach the conclusion of this guide, you’ll possess the expertise to wield both spies and mocks with precision, enhancing your Java testing arsenal.
At first glance, Mockito’s spy and mock functionalities may appear similar, but beneath the surface lies a fundamental difference that dictates their respective applications. Both tools serve as essential components in your testing toolkit, but understanding when and how to use each is key to effective unit testing.
The Fundamental Distinction
The fundamental distinction between a Mockito mock and a spy revolves around how they interact with the objects they represent. A mock is essentially a placeholder object that has no real implementation of methods. On the other hand, a spy is an actual instance of the class being tested, with real methods that can be invoked.
Mockito Mock: A Placeholder
Consider a mock object representing a database connection. When you use a mock, you’re creating an artificial object that simulates the behavior of the real database connection. You can define expectations and verify interactions without invoking the actual methods.
Mockito Spy: The Real Deal
Contrastingly, a spy is a genuine instance of the class, where the methods are real and functional. It allows you to retain the actual behavior of the methods while enabling you to track and verify interactions.
What is the Difference Between Spy and Mock? Deconstructing the Nuances
The distinction between a spy and a mock goes beyond their fundamental nature. Delving deeper, we find nuanced differences in their application, usage, and the scenarios where they shine.
Mocks: Perfect for Isolation
Mocks excel when you need to isolate a specific unit of code from its dependencies. They allow you to define expectations and behaviors precisely for the methods you’re testing. This isolation is particularly valuable when testing complex interactions.
Spies: Realism and Verification
Spies, on the other hand, come into play when you want to maintain the real behavior of methods while still tracking their interactions. They offer the flexibility of verifying method invocations, while also ensuring that the tested component’s logic remains intact.
The Key Differences Between Mock and Spy in Java
Example: Using Mockito Mock
Consider a scenario where you’re testing a payment processing module. You can use a mock to simulate a payment gateway’s behavior without actually interacting with the real payment gateway:
// Creating a mock object
PaymentGateway paymentGateway = Mockito.mock(PaymentGateway.class);
// Defining expectations
Mockito.when(paymentGateway.processPayment(100.0)).thenReturn(true);
// Invoking the method being tested
PaymentProcessor paymentProcessor = new PaymentProcessor(paymentGateway);
boolean result = paymentProcessor.processPayment(100.0);
// Verifying expectations
Assert.assertTrue(result);
Mockito.verify(paymentGateway).processPayment(100.0);
Example: Utilizing Mockito Spy
Now, imagine you’re testing a complex service that involves database interactions. By using a spy, you can retain the real behavior of the database methods while verifying their usage:
// Creating a spy object
DatabaseService databaseService = Mockito.spy(DatabaseService.class);
// Invoking the method being tested
boolean result = databaseService.saveData(“sample data”);
// Verifying method invocation
Mockito.verify(databaseService).saveData(“sample data”);
// Additional assertions on the result
Assert.assertTrue(result);
Exploring Real-World Use Cases of Mockito Spy and Mock
Now that we’ve established a solid understanding of the fundamental differences between spies and mocks in Mockito, let’s delve deeper into real-world scenarios where each of these tools shines.
By unraveling these use cases, you’ll gain valuable insights into how to leverage spies and mocks effectively within your Java testing endeavors. Explore more in the next video
Imagine you’re working on a shopping cart application where you need to test the interaction between the cart and inventory management. Here’s where a mock comes into play. You want to isolate the cart’s behavior without involving the real inventory management system:
// Creating a mock object for InventoryManager
InventoryManager inventoryManager = Mockito.mock(InventoryManager.class);
// Defining expectations for unavailable items
Mockito.when(inventoryManager.isItemAvailable(“item123”)).thenReturn(false);
// Creating a cart object with the mock inventory manager
ShoppingCart cart = new ShoppingCart(inventoryManager);
// Adding an item that is unavailable
boolean result = cart.addItem(“item123”);
// Verifying interaction with the mock
Assert.assertFalse(result);
Mockito.verify(inventoryManager).isItemAvailable(“item123”);

Realism and Interaction Verification with Mockito Spy
Consider a scenario where you’re developing a social media platform, and you need to test user profile interactions with the friend list feature. Spies are your tool of choice, as you want to maintain the real behavior of the user profile while ensuring the friend list interactions are verified:
// Creating a spy object for UserProfile
UserProfile userProfile = Mockito.spy(UserProfile.class);
// Invoking the method being tested
userProfile.addFriend(“user456”);
// Verifying interaction with the spy
Mockito.verify(userProfile).addFriend(“user456”);
// Additional assertions on the friend count
Assert.assertEquals(1, userProfile.getFriendCount());
Conclusion
The power of mocks lies in their ability to isolate units of code and define precise expectations, making them invaluable when testing intricate interactions. On the other hand, spies offer the advantage of realism, allowing you to maintain the actual behavior of methods while ensuring interaction tracking and verification.
Armed with this knowledge, you’re now equipped to navigate the complex landscape of unit testing with confidence. You possess the discernment to select the right tool for the job, whether it’s the focused isolation of a mock or the interaction transparency of a spy.
By seamlessly integrating Mockito’s spies and mocks into your Java testing practices, you elevate your code’s reliability and fortitude, enabling your applications to stand resilient against the challenges of real-world usage.