0
0
JUnittesting~15 mins

doReturn and doThrow in JUnit - Deep Dive

Choose your learning style9 modes available
Overview - doReturn and doThrow
What is it?
In JUnit testing with Mockito, doReturn and doThrow are methods used to control how mocked objects behave. doReturn lets you specify a value to return when a method is called, while doThrow lets you specify an exception to be thrown. These help simulate different scenarios without running real code.
Why it matters
Without doReturn and doThrow, tests would rely on actual implementations, making tests slow, unreliable, or hard to isolate. They let you test how your code reacts to different responses or errors, ensuring your program handles all cases safely.
Where it fits
Before learning doReturn and doThrow, you should understand basic JUnit tests and Mockito mocks. After mastering these, you can explore advanced mocking techniques like spying, argument captors, and verifying call order.
Mental Model
Core Idea
doReturn and doThrow let you predefine how a mock behaves by returning values or throwing exceptions to simulate real-world scenarios in tests.
Think of it like...
Imagine you have a robot assistant that can be programmed to either hand you a tool or shout an alarm when you ask for something. doReturn programs it to hand you the tool, doThrow programs it to shout an alarm.
Mocked Method Call
  ├─ doReturn(value) ──> Returns the specified value
  └─ doThrow(exception) ──> Throws the specified exception
Build-Up - 6 Steps
1
FoundationUnderstanding Mockito Mocks Basics
🤔
Concept: Learn what mocks are and how they replace real objects in tests.
Mocks are fake objects that imitate real ones. They let you control method responses without running real code. For example, mocking a database call returns preset data instantly.
Result
You can isolate the code under test from external dependencies.
Understanding mocks is key because doReturn and doThrow only work on mocks to simulate behavior.
2
FoundationBasic Stubbing with thenReturn
🤔
Concept: Learn how to make a mock method return a value using thenReturn.
Using Mockito, you write: when(mock.method()).thenReturn(value); This means calling method() returns value.
Result
The mock returns the value you set whenever the method is called.
Knowing thenReturn sets the stage for why doReturn is sometimes needed as an alternative.
3
IntermediateUsing doReturn for Stubbing
🤔Before reading on: do you think doReturn is just another way to write thenReturn? Commit to your answer.
Concept: doReturn is an alternative to thenReturn, useful in special cases like spying or final methods.
doReturn(value).when(mock).method(); sets the method to return value. It avoids calling the real method during stubbing, unlike thenReturn.
Result
The mock returns the specified value without executing the real method during setup.
Understanding doReturn prevents errors when stubbing methods that cause side effects or cannot be stubbed with thenReturn.
4
IntermediateUsing doThrow to Simulate Exceptions
🤔Before reading on: can you use thenReturn to make a mock throw an exception? Commit to your answer.
Concept: doThrow lets you make a mock method throw an exception when called, simulating error conditions.
doThrow(new Exception()).when(mock).method(); means calling method() throws that exception.
Result
The mock throws the specified exception, letting you test error handling.
Knowing how to simulate exceptions is crucial to test how your code reacts to failures.
5
AdvancedWhen to Prefer doReturn Over thenReturn
🤔Before reading on: do you think thenReturn always works fine for all mocks? Commit to your answer.
Concept: doReturn is preferred when stubbing spies or final methods where thenReturn causes real method calls or errors.
Spies wrap real objects. thenReturn calls the real method during stubbing, which can cause side effects or exceptions. doReturn avoids this by not calling the real method.
Result
Tests become safer and more predictable when using doReturn in these cases.
Knowing this prevents flaky tests and hard-to-find bugs caused by unintended real method calls.
6
ExpertCombining doReturn and doThrow in Complex Tests
🤔Before reading on: can you chain doReturn and doThrow on the same mock method for different calls? Commit to your answer.
Concept: You can program mocks to return values or throw exceptions on different calls to simulate complex scenarios.
Example: doReturn(1).doThrow(new RuntimeException()).when(mock).method(); means first call returns 1, second call throws exception.
Result
You can test how your code handles sequences of success and failure.
Understanding this unlocks powerful test scenarios that mimic real-world unpredictable behavior.
Under the Hood
Mockito creates proxy objects that intercept method calls on mocks. doReturn and doThrow configure these proxies to respond with preset values or exceptions without executing real code. doReturn avoids calling the real method during stubbing, unlike thenReturn, which calls the method once to capture the return value.
Why designed this way?
Mockito's design balances ease of use and flexibility. thenReturn is simple for most cases but fails with spies or final methods. doReturn was introduced to handle these edge cases by avoiding real method calls during stubbing, preventing side effects and errors.
┌─────────────┐
│ Test Code   │
└─────┬───────┘
      │ calls method()
┌─────▼───────┐
│ Mockito Mock│
│ Proxy       │
└─────┬───────┘
      │ configured by
      │ doReturn or doThrow
      ▼
┌─────────────┐
│ Returns     │
│ value or    │
│ throws ex   │
Myth Busters - 3 Common Misconceptions
Quick: does thenReturn always avoid calling the real method when stubbing? Commit yes or no.
Common Belief:thenReturn never calls the real method during stubbing.
Tap to reveal reality
Reality:thenReturn calls the real method once during stubbing to get the return value, which can cause side effects or errors.
Why it matters:Using thenReturn on spies or final methods can cause tests to fail or behave unpredictably.
Quick: can doThrow be replaced by thenThrow in all cases? Commit yes or no.
Common Belief:doThrow and thenThrow are interchangeable in all mocking scenarios.
Tap to reveal reality
Reality:doThrow is preferred when stubbing void methods or spies to avoid calling real methods; thenThrow may call real methods causing side effects.
Why it matters:Misusing thenThrow can cause tests to execute unwanted real code, breaking isolation.
Quick: can you chain doReturn and doThrow on the same method for multiple calls? Commit yes or no.
Common Belief:Mocks can only be stubbed to return one behavior per method.
Tap to reveal reality
Reality:Mockito allows chaining doReturn and doThrow to simulate different behaviors on sequential calls.
Why it matters:Not knowing this limits test coverage for scenarios with changing responses.
Expert Zone
1
doReturn avoids calling the real method during stubbing, which is critical when the real method has side effects or depends on external state.
2
doThrow is the only way to stub void methods to throw exceptions, as thenThrow cannot be used with void methods directly.
3
Chaining doReturn and doThrow allows simulating complex sequences like retries, failures, and recovery in tests.
When NOT to use
Avoid doReturn and doThrow when testing pure unit logic without external dependencies; prefer direct method calls or simpler stubbing. For integration tests, use real objects or specialized test doubles instead.
Production Patterns
In real projects, doReturn is used with spies to safely stub partial mocks. doThrow is used to test error handling paths, especially for exceptions from external services or APIs. Chaining behaviors simulate flaky network calls or intermittent failures.
Connections
Exception Handling
doThrow simulates exceptions, directly linking to how code handles errors.
Understanding doThrow deepens your grasp of exception flow and recovery in software.
Dependency Injection
Mocks configured with doReturn and doThrow replace real dependencies injected into classes.
Knowing this connection clarifies how testing isolates units by controlling dependencies.
Behavioral Psychology
Programming mocks to respond differently on calls mirrors conditioning behaviors in psychology.
This cross-domain link shows how predictable responses help test and train systems, whether software or humans.
Common Pitfalls
#1Using thenReturn on a spy causes the real method to execute during stubbing, causing side effects.
Wrong approach:when(spy.method()).thenReturn(value);
Correct approach:doReturn(value).when(spy).method();
Root cause:Misunderstanding that thenReturn calls the real method once during stubbing.
#2Trying to use thenThrow on a void method, which is not supported.
Wrong approach:when(mock.voidMethod()).thenThrow(new Exception());
Correct approach:doThrow(new Exception()).when(mock).voidMethod();
Root cause:Not knowing that thenThrow cannot stub void methods.
#3Assuming mocks can only have one fixed behavior per method call.
Wrong approach:doReturn(1).when(mock).method(); doReturn(2).when(mock).method();
Correct approach:doReturn(1).doReturn(2).when(mock).method();
Root cause:Lack of awareness about chaining stubbing calls for sequential behaviors.
Key Takeaways
doReturn and doThrow let you control mock behavior by returning values or throwing exceptions without running real code.
doReturn is essential when stubbing spies or final methods to avoid unwanted real method calls during setup.
doThrow is the correct way to simulate exceptions, especially for void methods, enabling robust error handling tests.
Chaining doReturn and doThrow allows simulating complex sequences of success and failure in tests.
Misusing thenReturn or thenThrow can cause tests to execute real code, leading to flaky or broken tests.