Choosing the right test double in JUnit - Build an Automation Script
import static org.mockito.Mockito.*; import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; interface PaymentService { boolean processPayment(double amount); } class OrderProcessor { private final PaymentService paymentService; public OrderProcessor(PaymentService paymentService) { this.paymentService = paymentService; } public boolean placeOrder(double amount) { return paymentService.processPayment(amount); } } public class OrderProcessorTest { private PaymentService paymentServiceMock; private OrderProcessor orderProcessor; @BeforeEach void setup() { paymentServiceMock = mock(PaymentService.class); orderProcessor = new OrderProcessor(paymentServiceMock); } @Test void testPlaceOrderCallsProcessPayment() { when(paymentServiceMock.processPayment(anyDouble())).thenReturn(true); boolean result = orderProcessor.placeOrder(100.0); assertTrue(result, "placeOrder should return true"); verify(paymentServiceMock, times(1)).processPayment(100.0); } }
This test uses Mockito to create a mock of the PaymentService interface. In the @BeforeEach method, the mock is created and injected into the OrderProcessor instance.
In the test method, we configure the mock to return true for any payment amount using when(...).thenReturn(true). Then we call placeOrder(100.0) and assert that it returns true.
Finally, we verify that the processPayment method was called exactly once with the argument 100.0. This confirms that OrderProcessor correctly delegates payment processing to the PaymentService.
This approach uses a mock test double to isolate OrderProcessor from the real PaymentService, allowing us to test behavior without side effects.
Now add data-driven testing with 3 different payment amounts: 50.0, 100.0, and 200.0
Practice
Solution
Step 1: Understand the purpose of mocks
Mocks are used to fake behavior and verify interactions, such as method calls.Step 2: Compare with other test doubles
Stubs provide fixed responses, fakes have working implementations, spies record calls but mocks are designed for verification.Final Answer:
Mock -> Option AQuick Check:
Verify calls = Mock [OK]
- Confusing stubs with mocks
- Using fake when verification is needed
- Thinking spies are the same as mocks
Solution
Step 1: Identify stub creation syntax
Stubs return fixed data; in Mockito, use when(...).thenReturn(...) to stub a method.Step 2: Check other options
Verify checks calls, mock creates mocks, spy wraps real objects; only when().thenReturn() stubs.Final Answer:
when(service.getData()).thenReturn("data"); -> Option BQuick Check:
Stub method = when().thenReturn() [OK]
- Using verify() to stub methods
- Confusing mock() with stub setup
- Using spy() instead of stub
List<String> list = mock(List.class); when(list.size()).thenReturn(5); assertEquals(5, list.size());
Solution
Step 1: Analyze mock behavior
The list is mocked, and size() is stubbed to return 5.Step 2: Check assertion
assertEquals(5, list.size()) compares 5 with stubbed return 5, so it passes.Final Answer:
Test passes because size() returns 5 -> Option AQuick Check:
Stubbed method returns set value [OK]
- Assuming default mock returns 0
- Expecting real method call on mock
- Confusing mock with spy behavior
@Test
void testServiceCall() {
Service service = mock(Service.class);
service.process();
verify(service.process());
}Solution
Step 1: Check verify syntax
verify() expects the mock object, then method call separately: verify(service).process();Step 2: Identify error in code
Current code calls verify(service.process()), which is incorrect syntax and causes compile error.Final Answer:
Incorrect use of verify; should be verify(service).process(); -> Option DQuick Check:
verify syntax = verify(mock).method() [OK]
- Calling verify with method call inside
- Forgetting to mock the object
- Confusing stub and verify usage
Solution
Step 1: Understand test goal
We want to avoid real charges but verify the payment method was called.Step 2: Choose test double type
Mocks fake behavior and verify calls, perfect for checking method calls without real effects.Step 3: Compare other options
Stubs return fixed data but don't verify calls; fakes have real logic; spies call real methods, risking real charges.Final Answer:
Use a mock to verify the payment method call -> Option CQuick Check:
Verify calls without real effect = Mock [OK]
- Using spy risks real external calls
- Using stub misses call verification
- Choosing fake adds unnecessary complexity
Ready to prove it?
Pass the test and this pattern moves unknown
