How do I mock exceptions in JUnit tests?

In JUnit tests, you usually don’t “mock” exceptions directly. Instead, you either:

  1. Assert that real code throws an exception, or
  2. Configure a mock dependency to throw an exception.

1. Assert that code throws an exception

With JUnit 5, use assertThrows.

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

class MyServiceTest {

    @Test
    void shouldThrowException() {
        IllegalArgumentException exception = assertThrows(
                IllegalArgumentException.class,
                () -> {
                    throw new IllegalArgumentException("Invalid input");
                }
        );

        assertEquals("Invalid input", exception.getMessage());
    }
}

assertThrows verifies that the code inside the lambda throws the expected exception type.

2. Mock a dependency to throw an exception with Mockito

If your class depends on another object, you can configure the mock to throw an exception.

import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.when;

class UserServiceTest {

    @Test
    void shouldThrowWhenRepositoryFails() {
        UserRepository repository = Mockito.mock(UserRepository.class);

        when(repository.findById(1L))
                .thenThrow(new RuntimeException("Database error"));

        UserService service = new UserService(repository);

        assertThrows(
                RuntimeException.class,
                () -> service.getUser(1L)
        );
    }
}

3. Mock exceptions for void methods

For void methods, use doThrow.

import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.doThrow;

class NotificationServiceTest {

    @Test
    void shouldThrowWhenEmailFails() {
        EmailClient emailClient = Mockito.mock(EmailClient.class);

        doThrow(new RuntimeException("Email failed"))
                .when(emailClient)
                .sendEmail("[email protected]");

        NotificationService service = new NotificationService(emailClient);

        assertThrows(
                RuntimeException.class,
                () -> service.notifyUser("[email protected]")
        );
    }
}

4. Check the exception message

You can capture the thrown exception and verify its message.

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

class CalculatorTest {

    @Test
    void shouldThrowArithmeticException() {
        ArithmeticException exception = assertThrows(
                ArithmeticException.class,
                () -> {
                    int result = 10 / 0;
                }
        );

        assertEquals("/ by zero", exception.getMessage());
    }
}

5. JUnit 4 alternative

If you are using JUnit 4, you can use the expected attribute.

import org.junit.Test;

public class CalculatorTest {

    @Test(expected = ArithmeticException.class)
    public void shouldThrowArithmeticException() {
        int result = 10 / 0;
    }
}

However, in JUnit 4, ExpectedException or AssertJ is better if you need to check the message.

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

public class CalculatorTest {

    @Rule
    public ExpectedException exception = ExpectedException.none();

    @Test
    public void shouldThrowWithMessage() {
        exception.expect(IllegalArgumentException.class);
        exception.expectMessage("Invalid input");

        throw new IllegalArgumentException("Invalid input");
    }
}

Quick rule of thumb

  • Use assertThrows when testing your own method throws an exception.
  • Use when(...).thenThrow(...) for mocked methods that return a value.
  • Use doThrow(...).when(...) for mocked void methods.

For modern Java projects, prefer JUnit 5 + Mockito:

assertThrows(SomeException.class, () -> service.method());

How do I test exceptions with assertThrows()?

Testing Exceptions with assertThrows() in JUnit 5

Use assertThrows() when you expect a piece of code to throw a specific exception.

Basic Syntax

ExceptionType exception = assertThrows(
        ExceptionType.class,
        () -> {
            // code that should throw the exception
        }
);

For JUnit 5, import it like this:

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertThrows;

Simple Example

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertThrows;

class DivisionTest {

    @Test
    void divideByZeroThrowsArithmeticException() {
        assertThrows(ArithmeticException.class, () -> {
            int result = 10 / 0;
        });
    }
}

If 10 / 0 throws an ArithmeticException, the test passes.

If no exception is thrown, or a different exception is thrown, the test fails.


Checking the Exception Message

assertThrows() returns the thrown exception, so you can inspect it.

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

class UserServiceTest {

    @Test
    void rejectsInvalidUserId() {
        IllegalArgumentException exception = assertThrows(
                IllegalArgumentException.class,
                () -> validateUserId(-1)
        );

        assertEquals("User ID must be positive", exception.getMessage());
    }

    private void validateUserId(int userId) {
        if (userId <= 0) {
            throw new IllegalArgumentException("User ID must be positive");
        }
    }
}

Testing a Method That Throws an Exception

Suppose you have this method:

public int divide(int a, int b) {
    if (b == 0) {
        throw new IllegalArgumentException("Divider cannot be zero");
    }

    return a / b;
}

You can test it like this:

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

class CalculatorTest {

    private final Calculator calculator = new Calculator();

    @Test
    void divideThrowsExceptionWhenDividerIsZero() {
        IllegalArgumentException exception = assertThrows(
                IllegalArgumentException.class,
                () -> calculator.divide(10, 0)
        );

        assertEquals("Divider cannot be zero", exception.getMessage());
    }
}

Short Form

If you only care that the exception is thrown, you do not need to store it:

@Test
void invalidInputThrowsException() {
    assertThrows(
            IllegalArgumentException.class,
            () -> someMethod("invalid")
    );
}

Important Notes

  • The code that should throw the exception goes inside the lambda: () -> ...
  • The expected exception type goes first: IllegalArgumentException.class
  • The test passes only if that exception type, or a subclass of it, is thrown.
  • If you want an exact exception type match, use assertThrowsExactly().

Example:

@Test
void throwsExactlyIllegalArgumentException() {
    assertThrowsExactly(
            IllegalArgumentException.class,
            () -> someMethod("invalid")
    );
}

You would need this import:

import static org.junit.jupiter.api.Assertions.assertThrowsExactly;

Common Mistake

Do not call the method before assertThrows():

// Wrong
someMethod("invalid");
assertThrows(IllegalArgumentException.class, () -> {});

Instead, call the method inside the lambda:

// Correct
assertThrows(
        IllegalArgumentException.class,
        () -> someMethod("invalid")
);

Summary

Use assertThrows() like this:

@Test
void methodThrowsExpectedException() {
    Exception exception = assertThrows(
            Exception.class,
            () -> methodThatShouldThrow()
    );

    assertEquals("Expected message", exception.getMessage());
}

It verifies that the code throws the expected exception and optionally lets you check details such as the exception message.