What's the difference between a mock & stub?

 

Both mocks and stubs are concepts used in testing, especially in the context of unit testing and test doubles. They are used to isolate the code under test from its dependencies.

Mock: A mock is an object that simulates the behavior of a real object or component, allowing you to set expectations on its methods and verify interactions. Mocks are often used to ensure that specific methods are called with the correct parameters during testing.

Stub: A stub is an object that provides pre-defined responses to method calls, typically to isolate the code under test from complex behavior or external systems. Stubs allow you to control the behavior of certain methods for the purpose of testing.

Example:

Let's consider a simple example where you're testing a PaymentProcessor class that interacts with a PaymentGateway object to process payments. The PaymentGateway communicates with a payment provider to process actual payments.

java
public interface PaymentGateway { boolean processPayment(double amount); } public class PaymentProcessor { private PaymentGateway gateway; public PaymentProcessor(PaymentGateway gateway) { this.gateway = gateway; } public boolean processOrder(double totalAmount) { if (totalAmount <= 0) { return false; } return gateway.processPayment(totalAmount); } }

In a unit test for the PaymentProcessor class, you might want to isolate it from the actual payment gateway to focus on testing its behavior. Here's how mocks and stubs could be used in this scenario:

Mock Example:

You want to ensure that the processPayment method of the PaymentGateway is called with the correct amount during testing. You use a mock to set this expectation and verify the interaction:

java
import org.junit.Test; import static org.mockito.Mockito.*; public class PaymentProcessorTest { @Test public void testProcessOrderCallsPaymentGateway() { PaymentGateway mockGateway = mock(PaymentGateway.class); PaymentProcessor processor = new PaymentProcessor(mockGateway); double totalAmount = 100.0; processor.processOrder(totalAmount); verify(mockGateway).processPayment(totalAmount); } }

Stub Example:

You want to test how the PaymentProcessor handles different scenarios, including unsuccessful payments. You use a stub to control the behavior of the processPayment method:

java
import org.junit.Test; import static org.junit.Assert.*; import static org.mockito.Mockito.*; public class PaymentProcessorTest { @Test public void testProcessOrderWithUnsuccessfulPayment() { PaymentGateway stubGateway = mock(PaymentGateway.class); when(stubGateway.processPayment(anyDouble())).thenReturn(false); // Stub behavior PaymentProcessor processor = new PaymentProcessor(stubGateway); double totalAmount = 0.0; // Negative amount assertFalse(processor.processOrder(totalAmount)); verify(stubGateway).processPayment(totalAmount); } }

In this example, the when(stubGateway.processPayment(anyDouble())).thenReturn(false) line sets up the stubbed behavior for the processPayment method, returning false for any amount. This allows you to test how the PaymentProcessor class handles an unsuccessful payment scenario without involving the actual payment processing.

In summary, mocks are used to verify interactions and expectations, while stubs are used to control behavior and isolate code for testing. Both are important tools in unit testing to ensure the correctness of your code.

Comments