What if you could test complex parts without waiting or risking real failures?
Why Choosing the right test double in JUnit? - Purpose & Use Cases
Imagine testing a car's navigation system by manually driving through every possible route to check if directions are correct.
This manual testing is slow, tiring, and prone to mistakes. You might miss some routes or get inconsistent results because of traffic or weather changes.
Using the right test double lets you simulate parts of the system, like fake GPS signals or mocked traffic data, so you can test navigation logic quickly and reliably without real driving.
RealGPS gps = new RealGPS(); Navigation nav = new Navigation(gps); nav.start(); // drives real routes
MockGPS gps = new MockGPS(); Navigation nav = new Navigation(gps); nav.start(); // simulates routes instantly
It enables fast, repeatable, and controlled tests that catch bugs early without relying on real-world conditions.
When testing a payment system, using a stub for the bank API lets you simulate approvals or declines instantly, avoiding costly real transactions.
Manual testing of complex parts is slow and unreliable.
Choosing the right test double simulates dependencies effectively.
This leads to faster, safer, and more accurate tests.
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
