0
0
JUnittesting~15 mins

when().thenReturn() stubbing in JUnit - Deep Dive

Choose your learning style9 modes available
Overview - when().thenReturn() stubbing
What is it?
when().thenReturn() stubbing is a way to tell a test double (mock) what to do when a specific method is called. It lets you define a fixed response for a method call during testing, so you can control the behavior of dependencies. This helps isolate the code you want to test by replacing real objects with mocks that return predictable results.
Why it matters
Without stubbing, tests would depend on real objects that might be slow, unreliable, or hard to set up. This would make tests flaky and slow. Stubbing ensures tests run fast and consistently by simulating only the needed parts of the system. It helps developers find bugs quickly and confidently change code without breaking unrelated parts.
Where it fits
Before learning stubbing, you should understand unit testing basics and what mocks are. After mastering stubbing, you can learn advanced mocking techniques like argument matchers, verifying interactions, and using spies. This fits into the broader journey of writing reliable automated tests.
Mental Model
Core Idea
Stubbing with when().thenReturn() means pre-programming a mock to give a specific answer when a method is called during a test.
Think of it like...
It's like telling a friend exactly what to say when someone asks them a question during a play rehearsal, so the scene goes as planned without surprises.
┌───────────────┐
│ Mock Object   │
│───────────────│
│ when(method)  │
│ thenReturn(x) │
└──────┬────────┘
       │
       ▼
┌───────────────┐
│ Test Calls    │
│ method() → x  │
└───────────────┘
Build-Up - 6 Steps
1
FoundationUnderstanding Mocks and Stubs
🤔
Concept: Introduce mocks and stubs as fake objects used in tests to simulate real behavior.
Mocks are objects that imitate real objects in tests. Stubs are a type of mock that return fixed values when methods are called. This helps isolate the code under test by controlling external dependencies.
Result
Learners understand why and when to use mocks and stubs in testing.
Knowing the difference between mocks and stubs is key to writing focused and reliable tests.
2
FoundationBasic Syntax of when().thenReturn()
🤔
Concept: Learn the basic syntax to stub a method call using when().thenReturn() in JUnit with Mockito.
Use when(mock.method()).thenReturn(value) to tell the mock what to return when the method is called. For example: MyService mock = mock(MyService.class); when(mock.getData()).thenReturn("Hello"); Now, mock.getData() returns "Hello".
Result
Tests can control mock behavior with simple syntax.
Mastering this syntax unlocks the ability to simulate any method response easily.
3
IntermediateStubbing Methods with Arguments
🤔Before reading on: do you think when().thenReturn() can handle methods with any arguments or only fixed ones? Commit to your answer.
Concept: Learn how to stub methods that take arguments, including using exact values and argument matchers.
You can stub methods with specific arguments: when(mock.calculate(5)).thenReturn(10); This returns 10 only when calculate(5) is called. For flexible matching, use argument matchers: when(mock.calculate(anyInt())).thenReturn(20); This returns 20 for any integer argument.
Result
Mocks respond correctly based on method arguments.
Understanding argument matching prevents brittle tests and allows flexible stubbing.
4
IntermediateStubbing Multiple Calls Differently
🤔Before reading on: can when().thenReturn() return different values on consecutive calls? Guess yes or no.
Concept: Learn how to make a stub return different values on multiple calls to the same method.
Use thenReturn() with multiple values: when(mock.getNext()).thenReturn("First", "Second", "Third"); Each call to getNext() returns the next value in order. After the last, it returns the last value repeatedly.
Result
Mocks simulate changing behavior over time.
This helps test loops or retries where method results vary.
5
AdvancedStubbing Void Methods with doReturn()
🤔Before reading on: do you think when().thenReturn() works with void methods? Commit your answer.
Concept: Understand that when().thenReturn() cannot stub void methods and learn the alternative doReturn() syntax.
Void methods don't return values, so when().thenReturn() fails. Instead, use: doNothing().when(mock).voidMethod(); Or for stubbing behavior: doThrow(new Exception()).when(mock).voidMethod(); This controls void method behavior in tests.
Result
Tests can handle void methods correctly.
Knowing this prevents common errors and test failures with void methods.
6
ExpertAvoiding Common Stubbing Pitfalls
🤔Before reading on: do you think stubbing a method twice on the same mock overwrites or combines behaviors? Guess before reading.
Concept: Learn subtle behaviors like stubbing overwrites, default returns, and interaction with spies.
If you stub the same method twice, the last stub wins: when(mock.method()).thenReturn(1); when(mock.method()).thenReturn(2); mock.method() returns 2. Also, unstubbed methods return defaults (null, 0, false). Spies call real methods unless stubbed. Mixing stubs and spies requires care.
Result
Tests behave predictably without hidden surprises.
Understanding these subtleties avoids flaky tests and debugging headaches.
Under the Hood
Mockito creates a proxy object that intercepts method calls on the mock. When a method is called, it checks if a stub is defined for that method and arguments. If yes, it returns the stubbed value instead of executing real code. This interception happens at runtime using dynamic proxies or bytecode generation.
Why designed this way?
This design allows tests to replace real dependencies without changing production code. Using proxies keeps mocks lightweight and flexible. Alternatives like subclassing were less flexible and more error-prone. The dynamic approach supports complex stubbing and verification.
┌───────────────┐       ┌───────────────┐
│ Test Code     │──────▶│ Mock Proxy    │
│ Calls method()│       │ Intercepts    │
└───────────────┘       └──────┬────────┘
                                   │
                      ┌────────────▼───────────┐
                      │ Stub Lookup Table      │
                      │ (method + args → value)│
                      └────────────┬───────────┘
                                   │
                      ┌────────────▼───────────┐
                      │ Return stubbed value   │
                      └────────────────────────┘
Myth Busters - 4 Common Misconceptions
Quick: does when().thenReturn() execute the real method during stubbing? Commit yes or no.
Common Belief:People often think when().thenReturn() calls the real method when setting up stubs.
Tap to reveal reality
Reality:when().thenReturn() does NOT call the real method; it only records the stub behavior.
Why it matters:If the real method has side effects or is slow, thinking it runs during stubbing causes confusion and test errors.
Quick: can you stub private methods with when().thenReturn()? Commit yes or no.
Common Belief:Some believe you can stub private methods directly with when().thenReturn().
Tap to reveal reality
Reality:Mockito cannot stub private methods because it works via proxies that only intercept public or protected methods.
Why it matters:Trying to stub private methods leads to silent failures or unexpected behavior, wasting debugging time.
Quick: does stubbing a method twice combine the results or overwrite? Commit your guess.
Common Belief:Many think multiple stubs on the same method combine or add behaviors.
Tap to reveal reality
Reality:The last stub overwrites previous ones; only the last thenReturn() applies.
Why it matters:Misunderstanding this causes tests to behave unexpectedly when stubs are overwritten silently.
Quick: does when().thenReturn() work with void methods? Commit yes or no.
Common Belief:Some assume when().thenReturn() can stub void methods.
Tap to reveal reality
Reality:It cannot; void methods require doReturn(), doThrow(), or doNothing() syntax.
Why it matters:Using when().thenReturn() on void methods causes runtime errors and test failures.
Expert Zone
1
Stubbing with argument matchers requires all arguments to use matchers or none; mixing causes errors.
2
Mockito's default answer for unstubbed methods is to return zeros, nulls, or false, which can hide missing stubs.
3
Spies wrap real objects and call real methods unless stubbed, which can cause side effects if not handled carefully.
When NOT to use
Avoid when().thenReturn() for complex asynchronous or multi-threaded code where behavior depends on timing. Use specialized frameworks or integration tests instead. Also, do not use it for private or static methods; use PowerMock or refactor code.
Production Patterns
In real projects, when().thenReturn() is used to isolate units by mocking external services, databases, or APIs. It helps test error handling by stubbing exceptions. Combined with verify(), it ensures correct interactions. Teams use it in CI pipelines for fast, reliable tests.
Connections
Dependency Injection
when().thenReturn() stubbing builds on dependency injection by replacing real dependencies with mocks.
Understanding dependency injection helps grasp why stubbing is possible and useful for isolating code.
Functional Programming
Stubbing mimics pure functions by controlling outputs for given inputs.
Knowing pure functions clarifies why fixed return values in stubs make tests predictable and reliable.
Theater Rehearsal
Both involve preparing responses ahead of time to ensure smooth performance.
This cross-domain link shows how planning responses in advance reduces surprises, whether in code or plays.
Common Pitfalls
#1Stubbing a method but forgetting to mock the object.
Wrong approach:when(service.getData()).thenReturn("Hello"); // service is not a mock
Correct approach:MyService service = mock(MyService.class); when(service.getData()).thenReturn("Hello");
Root cause:Trying to stub a real object instead of a mock causes runtime errors because real objects cannot be stubbed.
#2Mixing raw values and argument matchers in stubbing.
Wrong approach:when(mock.calculate(anyInt(), 5)).thenReturn(10);
Correct approach:when(mock.calculate(anyInt(), eq(5))).thenReturn(10);
Root cause:Mockito requires all arguments to be either matchers or exact values; mixing causes errors.
#3Using when().thenReturn() on void methods.
Wrong approach:when(mock.voidMethod()).thenReturn(null);
Correct approach:doNothing().when(mock).voidMethod();
Root cause:Void methods do not return values, so when().thenReturn() is invalid and causes exceptions.
Key Takeaways
when().thenReturn() stubbing lets you control mock method outputs to isolate code during testing.
It uses simple syntax to predefine return values for method calls, making tests predictable and fast.
Argument matchers and multiple return values add flexibility to stubbing behavior.
Void methods require special handling with doReturn() or doNothing() syntax.
Understanding stubbing internals and pitfalls prevents common test errors and flaky tests.