skip to content

Why can't you use when(...).thenThrow(...) for a void method, and how do you stub a void method to throw?

level: middleimportance: must knowfreq 65%

answer

  1. void has no return → can't go inside when(...)
  2. doThrow(ex).when(mock).voidMethod()
  3. when(mock) returns the mock; next call is stubbed
  4. do-form is safe for spies (real method not run)
  5. doThrow().doNothing() chains void behaviour

basics

~10 s

A void method returns nothing, so you can't pass its call into when(...). Use the do-form instead: doThrow(new RuntimeException()).when(mock).doStuff();

solid answer

~30 s

when(mock.method()) requires an expression that returns a value to pass into when(...). A void method returns nothing, so when(mock.voidMethod()) doesn't even compile. Mockito provides the do-family for this: doThrow(exception).when(mock).voidMethod(). Here when(mock) returns the mock again and the method call after it is what gets stubbed, so no return value is needed. The same do-form also works for value-returning methods and is the recommended way to stub spies (so the real method isn't actually invoked during stubbing). You can pass an instance or a class to doThrow, and the checked-exception-must-be-declared rule still applies. doThrow().doNothing().when(mock).method() chains behaviour across consecutive calls.

go deeper

for a junior

Knows void methods need doThrow(...).when(mock).method() instead of when(...).thenThrow(...).

for a middle

Explains why when(...) can't take a void call and reads the do-form grammar correctly.

for a senior

Knows the do-form is also correct for spies because it avoids invoking the real method during stubbing, and can chain consecutive behaviours.

for a principal

Sets team conventions on do-form vs when-form, spy hygiene, and when spying signals a design smell worth refactoring.

## The problem with when() and void Mockito's `when(...)` is designed around a clever trick: you *call the method on the mock*, Mockito records that call internally, and the value you pass to `when(...)` is just the method's return value (Mockito ignores the value itself — it uses the recorded invocation). For example `when(repo.find(1L))` passes the return of `find` into `when`. A **`void`** method returns nothing. You literally cannot write `when(mock.save(x))` because `save` has no value to hand to `when(...)` — the code does not compile. So the whole `when(...).thenThrow(...)` grammar is unavailable for `void` methods. ## The do-family solution Mockito offers an alternate grammar where the stubbed call comes **last**, so a return value is never needed: ```java doThrow(new IllegalStateException("disk full")).when(mock).save(x); ``` Read it as: "do throw this exception, when the mock's `save(x)` is called." `when(mock)` returns the mock itself; the *next* method call (`save(x)`) is the one being stubbed. Because the stubbed method is invoked as a *statement* (not inside `when(...)`), `void` is fine. Siblings in the do-family: `doReturn(...)`, `doNothing()`, `doAnswer(...)`, `doCallRealMethod()`. `doNothing()` is the explicit "do nothing" (the default for voids) and is handy in a chain. ## Class or instance — same rules `doThrow` accepts an exception instance or a class, identical to `thenThrow`: the class form uses the no-arg constructor; the instance form gives you the message/cause. The **checked-exception constraint** also still holds — a checked exception must appear in the method's `throws` clause. ## Consecutive calls ```java doThrow(new TimeoutException()).doNothing().when(mock).flush(); // 1st flush() throws, 2nd onward does nothing ``` ## Why do-form matters for spies A **spy** wraps a *real* object: unstubbed methods run the real implementation. With `when(spy.method())`, Java must *evaluate* `spy.method()` to pass its result into `when(...)`, which **actually runs the real method** — possibly with side effects or exceptions — before you've stubbed it. The do-form (`doThrow(...).when(spy).method()`) never executes the real method during stubbing, so it is the safe, recommended choice for spies, and for any method whose real execution you must avoid. ## Summary - `void` methods can't use `when(...).thenThrow(...)` (no return value to pass in). - Use `doThrow(...).when(mock).voidMethod()`. - The do-form also works for returning methods and is required/safer for spies. - Same class-vs-instance options and the same checked-exception rule apply.

  • Why is the do-form preferred for spies?
    when(spy.m()) actually executes the real m() to obtain a value to pass into when(...); doThrow(...).when(spy).m() never runs the real method during stubbing.
  • Does the checked-exception rule still apply with doThrow?
    Yes — a checked exception must still be declared by the stubbed method, exactly as with thenThrow.

saying these in an interview costs you the question

  • Trying when(mock.voidMethod()).thenThrow(...) — it doesn't compile
  • Using when(spy.m()).thenReturn(...) on a spy, which runs the real method
  • Thinking doThrow only works for void (it works for returning methods too)

context