JUnit 5 Expected Exception: assertThrows() Example

When writing unit tests, it makes sense to check whether certain methods throw the expected exceptions when we supply invalid inputs or pre-conditions that are not satisfied. Junit 5 provides the following assertion methods for handling test exceptions. These method names are self-explanatory enough to suggest their usage. …

JUnit 5 Expected Exception Tests

When writing unit tests, it makes sense to check whether certain methods throw the expected exceptions when we supply invalid inputs or pre-conditions that are not satisfied. Junit 5 provides the following assertion methods for handling test exceptions. These method names are self-explanatory enough to suggest their usage. Please continue reading for a deeper understanding.

MethodDescription
assertThrows()Verifies that a particular type of exception (or its subclass) is thrown. The test passes if the exception is thrown and fails otherwise.
assertThrowsExactly()Verifies that only an exact type of exception is thrown. The test passes if the exception is thrown and fails otherwise.
assertDoesNotThrow()Asserts that the test block does not throw any exception.

The following quick reference snippet shows how to use these methods:

@Test
void testExpectedException() {

  // 1. assertThrows() checks for RuntimeException or its subclass ( i.e. IllegalArgumentException)
  // This "PASSES" because IllegalArgumentException extends RuntimeException
  ApplicationException thrown = Assertions.assertThrows(RuntimeException.class, () -> {
    // ... Code under test  ...
    throw new IllegalArgumentException("custom error message");
  });
  Assertions.assertEquals("custom error message", thrown.getMessage());


  // 2. assertThrowsExactly() checks exactly for RuntimeException only
  // This "FAILS" because assertion expects only RuntimeException instance
  RuntimeException thrown = Assertions.assertThrowsExactly(RuntimeException.class, () -> {
    // ... Code under test  ...
    throw new IllegalArgumentException("expected message");
  }


  //3. assertDoesNotThrow() should not see any exception
  assertDoesNotThrow(() -> {
    // ... Code under test  ...
  });
}

1. JUnit assertThrows() API

The assertThrows() method verifies that a particular type of exception (or any of its subclasses) is thrown when a code block is executed.

1.1. Method Syntax

The assertThrows() method asserts that execution of the supplied executable block or lambda expression throws an exception of the expectedType. It is an overloaded method and takes the following parameters.

static <T extends Throwable>T assertThrows(Class<T> expectedType, Executable executable)

static <T extends Throwable>T assertThrows(Class<T> expectedType, Executable executable, String message)

static <T extends Throwable>T assertThrows(Class<T> expectedType, Executable executable, Supplier<String> messageSupplier)
  • expectedType – Test code is expected to throw an exception of this type.
  • message – If the executable code does not throw any exception, this message will be printed along with the FAIL result.
  • messageSupplier – The message will be retrieved from it in case the test fails.

1.2. Matches Specified Exception or Its Child Exception

The assertThrows() will FAIL:

  • If no exception is thrown from the executable block
  • If an exception of a different type is thrown

For example, in below example "1" is a valid number so no exception will be thrown. This test will fail with the message in the console.

@Test
void testExpectedExceptionFail() {
 
  NumberFormatException thrown = Assertions.assertThrows(NumberFormatException.class, () -> {
    Integer.parseInt("1");
  }, "NumberFormatException error was expected");
}
Junit message

The assertThrows() will PASS:

  • If the code block throws an exception of the specified type or a subtype.
  • For example, if we are expecting IllegalArgumentException and the test throws NumberFormatException then also the test will PASS because NumberFormatException extends IllegalArgumentException class.

Note that if we pass Exception.class as the expected exception type, any exception thrown from the executable block will make the assertion PASS since Exception is the super-type for all exceptions.

Given below is a straightforward test that expects NumberFormatException to be thrown when the supplied code block is executed.

@Test
void testExpectedException() {

	NumberFormatException thrown = Assertions.assertThrows(NumberFormatException.class, () -> {
		Integer.parseInt("One");
	}, "NumberFormatException was expected");
	
	Assertions.assertEquals("For input string: \"One\"", thrown.getMessage());
}

@Test
void testExpectedExceptionWithParentType() {

	Assertions.assertThrows(IllegalArgumentException.class, () -> {
		Integer.parseInt("One");
	});
}
  • In testExpectedException, The executable code is Integer.parseInt("One") which throws NumberFormatException if method argument is not a valid numeric number. The assertThrows() the method expects – so this exception so the test result is PASS.
  • In testExpectedExceptionWithParentType, we are executing the same code but this time we are excepting IllegalArgumentException which is the parent of NumberFormatException. This test also passes.

2. JUnit assertThrowsExactly() API

The assertThrowsExactly() method is similar to assertThrows(), but it verifies that only the exact type of exception specified is thrown, and not any subclass.

Let’s modify the previous test testExpectedExceptionWithParentType(). It was PASS with assertThrows() method. When we match the exact exception type, then it should fail.

// FAIL with assertThrowsExactly()
// PASS with assertThrows()

@Test
void testExpectedExceptionWithParentType() {

	Assertions.assertThrowsExactly(IllegalArgumentException.class, () -> {   
		Integer.parseInt("One");
	});
}

3. JUnit assertDoesNotThrow()

The assertDoesNotThrow() method verifies that the block of code throws no exception. This is useful when we want to ensure that our code runs smoothly without any issues and can handle edge-cases such as negative inputs etc.

@Test
void testDivideDoesNotThrowException() {

    // Verify that user is created when input contains allowed patterns
    assertDoesNotThrow(() -> addUser(new User(...)));
}

4. Expected Exception @Rule in JUnit 4

In JUnit 4, we can use the @Rule annotation along with ExpectedException to assert exceptions. The following class rewrites the previous example in JUnit 4 syntax.

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

public class MyTestClass {

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

    @Test
    public void testExpectedException() {
        expectedException.expect(NumberFormatException.class);
        expectedException.expectMessage("For input string: \"One\"");
        Integer.parseInt("One");
    }

    @Test
    public void testExpectedExceptionWithParentType() {
        expectedException.expect(IllegalArgumentException.class);
        Integer.parseInt("One");
    }
}

Happy Learning !!

Source Code Download

Weekly Newsletter

Stay Up-to-Date with Our Weekly Updates. Right into Your Inbox.

Comments

Subscribe
Notify of
4 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.