Mockito
Unit Testing
Java
Exception Handling
Software Development

Mockito test a void method throws an exception

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

When a mocked void method should throw an exception, Mockito uses the doThrow(...).when(mock).method(...) style rather than the when(...).thenThrow(...) form used for non-void methods. The other important part of the test is asserting that your production code reacts correctly to that exception instead of just proving that the mock can throw.

Why Void Methods Need Different Syntax

Mockito's usual stubbing style looks like this:

java
when(service.findById(1L)).thenReturn(value);

That does not work for void methods because there is no return value to wrap in when(...). For void methods, use doThrow().

Basic Example

Suppose you have a collaborator with a void method:

java
public interface NotificationService {
    void sendEmail(String message);
}

To make that method throw during a test:

java
1import static org.mockito.Mockito.doThrow;
2import static org.junit.jupiter.api.Assertions.assertThrows;
3
4import org.junit.jupiter.api.Test;
5import org.mockito.Mockito;
6
7class NotificationServiceTest {
8    @Test
9    void voidMethodThrows() {
10        NotificationService service = Mockito.mock(NotificationService.class);
11
12        doThrow(new IllegalArgumentException("bad message"))
13            .when(service)
14            .sendEmail("hello");
15
16        assertThrows(IllegalArgumentException.class, () -> service.sendEmail("hello"));
17    }
18}

That is the core Mockito pattern for a void method that throws.

Testing Your Own Code, Not Just the Mock

Usually the more valuable test exercises a class that depends on the mocked service.

java
1public class AlertManager {
2    private final NotificationService notificationService;
3
4    public AlertManager(NotificationService notificationService) {
5        this.notificationService = notificationService;
6    }
7
8    public void sendAlert(String message) {
9        notificationService.sendEmail(message);
10    }
11}

Test:

java
1import static org.junit.jupiter.api.Assertions.assertThrows;
2import static org.mockito.Mockito.doThrow;
3import static org.mockito.Mockito.mock;
4
5import org.junit.jupiter.api.Test;
6
7class AlertManagerTest {
8    @Test
9    void sendAlertPropagatesFailure() {
10        NotificationService service = mock(NotificationService.class);
11        AlertManager manager = new AlertManager(service);
12
13        doThrow(new RuntimeException("SMTP down"))
14            .when(service)
15            .sendEmail("warning");
16
17        assertThrows(RuntimeException.class, () -> manager.sendAlert("warning"));
18    }
19}

Now the test verifies application behavior, not just Mockito syntax.

You Can Verify the Call Too

Sometimes you want both behaviors: the method should be called, and the call should fail.

java
1import static org.mockito.Mockito.doThrow;
2import static org.mockito.Mockito.mock;
3import static org.mockito.Mockito.verify;
4import static org.junit.jupiter.api.Assertions.assertThrows;
5
6import org.junit.jupiter.api.Test;
7
8class VerifyExampleTest {
9    @Test
10    void verifyCallBeforeFailure() {
11        NotificationService service = mock(NotificationService.class);
12
13        doThrow(new IllegalStateException("mail server offline"))
14            .when(service)
15            .sendEmail("test");
16
17        assertThrows(IllegalStateException.class, () -> service.sendEmail("test"));
18        verify(service).sendEmail("test");
19    }
20}

That can be useful when the exception path is part of a larger interaction sequence.

doAnswer Is Useful for More Complex Void Behavior

If the void method should throw only under certain argument conditions or needs custom side effects, doAnswer is another option:

java
1import static org.mockito.Mockito.doAnswer;
2import static org.mockito.Mockito.mock;
3import static org.junit.jupiter.api.Assertions.assertThrows;
4
5NotificationService service = mock(NotificationService.class);
6
7doAnswer(invocation -> {
8    String message = invocation.getArgument(0);
9    if (message.isBlank()) {
10        throw new IllegalArgumentException("blank message");
11    }
12    return null;
13}).when(service).sendEmail(org.mockito.ArgumentMatchers.anyString());
14
15assertThrows(IllegalArgumentException.class, () -> service.sendEmail(""));

That is helpful when you want the mock behavior to depend on the actual invocation.

Prefer assertThrows with Modern JUnit

Older examples often use @Test(expected = ...), but in modern JUnit 5, assertThrows is clearer because the assertion lives next to the code under test.

It also makes it easier to inspect the exception message if needed.

Common Pitfalls

  • Using when(...).thenThrow(...) on a void method is the classic Mockito mistake; use doThrow(...).when(...) instead.
  • Testing only that the mock throws can be low value if the real goal is to test how your service reacts to the failure.
  • Relying on outdated JUnit syntax makes examples harder to maintain in modern codebases.
  • Stubbing one argument value and calling the method with a different one means the exception will not be thrown as expected.
  • Forgetting that void methods can still be verified with verify(...) often leads to weaker tests than necessary.

Summary

  • For a void method that should throw, use doThrow(...).when(mock).voidMethod(...).
  • Use assertThrows to verify the exception path cleanly.
  • Prefer tests that exercise your own class's behavior when the mocked collaborator fails.
  • 'doAnswer is useful when the thrown exception depends on the actual call arguments.'
  • 'verify(...) still works with void methods and is often useful alongside exception assertions.'

Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.