# 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();
}

Use a Java Refactoring Tool

No license required

You can review this refactoring on your code without a license by installing jSparrow to your Eclipse IDE. Install the plug-in from Eclipse IDE: Eclipse Marketplace.

System-wide Refactoring

Do you want to automate this refactoring (and many more) to your system-wide code? The automatic application of this system-wide refactoring can be unlocked by acquiring your jSparrow license.

a drawn cute bird pointing at a graph that shows positive results

# Properties

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