# Replace JUnit ExpectedException with assertThrows

# Description

The ExpectedException.none() (opens new window) rule is deprecated since JUnit 4.13. The recommended alternative is to use assertThrows() (opens new window). This makes JUnit tests easier to understand and prevents scenarios where some parts of the test code are unreachable.

The goal of this rule is to replace expectedException.expect() with assertThrows. Additionally, new assertions are added for each invocation of expectMessage() (opens new window) and expectCause() (opens new window). See more examples in the section below.

Requirements

This rule requires one of the following libraries to be present:

  • junit:junit:4.13
  • org.junit.jupiter:junit-jupiter-api:5.0.0

# Benefits

Improves the tests readability. Helps migrating to JUnit 5.

# Tags

# Code Changes

# Testing the Exception Type

Pre

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

@Test
public void expectIOException() throws IOException {
    expectedException.expect(IOException.class);
    throwsIOException("Throw an IOException");
}

Post

@Test
public void expectIOException() {
    assertThrows(IOException.class, () -> throwsIOException("Throw an IOException"));
}

# Testing the Exception Message

Pre

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

@Test
public void expectIOException() throws IOException {
    expectedException.expect(IOException.class);
    expectedException.expectMessage("IO");
    throwsIOException("Throw an IOException");
}

Post

@Test
public void expectIOException() {
    IOException exception = assertThrows(IOException.class, 
        () -> throwsIOException("Throw an IOException"));
    assertTrue(exception.getMessage().contains("IO"));
}

# Using Hamcrest Matchers

Pre

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

@Test
public void expectIOException() throws IOException {
    expectedException.expect(IOException.class);
    expectedException.expectMessage(containsString("IO"));
    throwsIOException("Throw an IOException");
}

Post

@Test
public void expectIOException() {
    IOException exception = assertThrows(IOException.class, 
        () -> throwsIOException("Throw an IOException"));
    assertThat(exception.getMessage(), containsString("IO"));
}

# Testing Expected Cause

Pre

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

@Test
public void testingExceptionCause() throws IOException {
    Matcher<Throwable> isNotFileNotFoundException = not(is(new FileNotFoundException()));
    expectedException.expect(IOException.class);
    expectedException.expectCause(isNotFileNotFoundException);
    throwIOException();
}

Post

@Test
public void testingExceptionCause() {
    Matcher<Throwable> isNotFileNotFoundException = not(is(new FileNotFoundException()));
    IOException exception = assertThrows(IOException.class, () -> throwIOException());
    assertThat(exception.getCause(), isNotFileNotFoundException);
}

# Throwing Runtime Exceptions Explicitly

Pre

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

@Test
public void explicitlyThrowingRuntimeException() {
    expectedException.expect(NullPointerException.class);
    throw new NullPointerException();
}

Post

@Test
public void explicitlyThrowingRuntimeException() {
    assertThrows(NullPointerException.class, () -> {
        throw new NullPointerException();
    });
}

# Limitations

  • Expected Runtime exceptions are not supported unless it can be explicitly derived that the last statements throws the expected exception.
@Test
public void expectingRuntimeException() {
    expectedException.expect(NullPointerException.class);
    User user = userRepository.findById("10");
    setName("John")
    save(user);
    throwRuntimeException();
}

You Want To Have Those Changes Done Automatically?

The automatic application of this rule is supported in the following jSparrow version:

# Properties

Property Value
Rule ID ReplaceJUnitExpectedException
First seen in jSparrow version 3.24.0
Minimum Java version 8
Remediation cost 5 min