Reputation: 7475
Is there a better way to assert that a method throws an exception in JUnit 5?
Currently, I have to use a @Rule
in order to verify that my test throws an exception, but this doesn't work for the cases where I expect multiple methods to throw exceptions in my test.
Upvotes: 558
Views: 864889
Reputation: 38147
As mentioned in the comment by user1075613:
you might be interested to check AssertJ for checking exceptions at it is more flexible than JUnit5
and it also generates fitting error message. Example:
assertThatThrownBy(() -> someMethod(param1, param2))
.isInstanceOf(NullPointerException.class);
Upvotes: 1
Reputation: 5729
TL;DR: If you are on JUnit 5.8.0+ version, you should use assertThrowsExactly()
instead of assertThrows()
to match the exact exception type.
assertThrowsExactly(FileNotFoundException.class, () -> service.blah());
You can use assertThrows()
, But with assertThrows
your assertion will pass even if the thrown exception is of child type.
This is because, JUnit 5 checks exception type by calling Class.isIntance(..)
, Class.isInstance(..)
will return true even if the thrown exception is of a child type.
The workaround for this is to assert on Class:
Throwable throwable = assertThrows(Throwable.class, () -> {
service.readFile("sampleFile.txt");
});
assertEquals(FileNotFoundException.class, throwable.getClass());
Upvotes: 52
Reputation: 7475
You can use assertThrows()
, which allows you to test multiple exceptions within the same test. With support for lambdas in Java 8, this is the canonical way to test for exceptions in JUnit.
Per the JUnit docs:
import static org.junit.jupiter.api.Assertions.assertThrows;
@Test
void exceptionTesting() {
MyException thrown = assertThrows(
MyException.class,
() -> myObject.doThing(),
"Expected doThing() to throw, but it didn't"
);
assertTrue(thrown.getMessage().contains("Stuff"));
}
Upvotes: 1000
Reputation: 713
This is what I do when testing to make sure an exception has been thrown
//when
final var tripConsumer = new BusTripConsumer(inputStream);
final Executable executable = () -> tripConsumer.deserialiseTripData();
//then
assertThrows(IllegalArgumentException.class, executable);
Upvotes: 3
Reputation: 162
My solution:
protected <T extends Throwable> void assertExpectedException(ThrowingRunnable methodExpectedToFail, Class<T> expectedThrowableClass,
String expectedMessage) {
T exception = assertThrows(expectedThrowableClass, methodExpectedToFail);
assertEquals(expectedMessage, exception.getMessage());
}
And you can call it like this:
assertExpectedException(() -> {
carService.findById(id);
}, IllegalArgumentException.class, "invalid id");
Upvotes: 3
Reputation: 249
An even simpler one liner. No lambda expressions or curly braces required for this example using Java 8 and JUnit 5
import static org.junit.jupiter.api.Assertions.assertThrows;
@Test
void exceptionTesting() {
assertThrows(MyException.class, myStackObject::doStackAction, "custom message if assertion fails...");
// note, no parenthesis on doStackAction ex ::pop NOT ::pop()
}
Upvotes: 9
Reputation: 1670
Here is an easy way.
@Test
void exceptionTest() {
try{
model.someMethod("invalidInput");
fail("Exception Expected!");
}
catch(SpecificException e){
assertTrue(true);
}
catch(Exception e){
fail("wrong exception thrown");
}
}
It only succeeds when the Exception you expect is thrown.
Upvotes: -11
Reputation: 1096
I think this is an even simpler example
List<String> emptyList = new ArrayList<>();
Optional<String> opt2 = emptyList.stream().findFirst();
assertThrows(NoSuchElementException.class, () -> opt2.get());
Calling get()
on an optional containing an empty ArrayList
will throw a NoSuchElementException
. assertThrows
declares the expected exception and provides a lambda supplier (takes no arguments and returns a value).
Thanks to @prime for his answer which I hopefully elaborated on.
Upvotes: 12
Reputation: 1288
Now Junit5 provides a way to assert the exceptions
You can test both general exceptions and customized exceptions
A general exception scenario:
ExpectGeneralException.java
public void validateParameters(Integer param ) {
if (param == null) {
throw new NullPointerException("Null parameters are not allowed");
}
}
ExpectGeneralExceptionTest.java
@Test
@DisplayName("Test assert NullPointerException")
void testGeneralException(TestInfo testInfo) {
final ExpectGeneralException generalEx = new ExpectGeneralException();
NullPointerException exception = assertThrows(NullPointerException.class, () -> {
generalEx.validateParameters(null);
});
assertEquals("Null parameters are not allowed", exception.getMessage());
}
You can find a sample to test CustomException here : assert exception code sample
ExpectCustomException.java
public String constructErrorMessage(String... args) throws InvalidParameterCountException {
if(args.length!=3) {
throw new InvalidParameterCountException("Invalid parametercount: expected=3, passed="+args.length);
}else {
String message = "";
for(String arg: args) {
message += arg;
}
return message;
}
}
ExpectCustomExceptionTest.java
@Test
@DisplayName("Test assert exception")
void testCustomException(TestInfo testInfo) {
final ExpectCustomException expectEx = new ExpectCustomException();
InvalidParameterCountException exception = assertThrows(InvalidParameterCountException.class, () -> {
expectEx.constructErrorMessage("sample ","error");
});
assertEquals("Invalid parametercount: expected=3, passed=2", exception.getMessage());
}
Upvotes: 34
Reputation: 15564
In Java 8 and JUnit 5 (Jupiter) we can assert for exceptions as follows.
Using org.junit.jupiter.api.Assertions.assertThrows
public static < T extends Throwable > T assertThrows(Class< T > expectedType, Executable executable)
Asserts that execution of the supplied executable throws an exception of the expectedType and returns the exception.
If no exception is thrown, or if an exception of a different type is thrown, this method will fail.
If you do not want to perform additional checks on the exception instance, simply ignore the return value.
@Test
public void itShouldThrowNullPointerExceptionWhenBlahBlah() {
assertThrows(NullPointerException.class,
()->{
//do whatever you want to do here
//ex : objectName.thisMethodShoulThrowNullPointerExceptionForNullParameter(null);
});
}
That approach will use the Functional Interface Executable
in org.junit.jupiter.api
.
Refer :
Upvotes: 172
Reputation: 2791
You can use assertThrows()
. My example is taken from the docs http://junit.org/junit5/docs/current/user-guide/
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
....
@Test
void exceptionTesting() {
Throwable exception = assertThrows(IllegalArgumentException.class, () -> {
throw new IllegalArgumentException("a message");
});
assertEquals("a message", exception.getMessage());
}
Upvotes: 27
Reputation: 877
They've changed it in JUnit 5 (expected: InvalidArgumentException, actual: invoked method) and code looks like this one:
@Test
public void wrongInput() {
Throwable exception = assertThrows(InvalidArgumentException.class,
()->{objectName.yourMethod("WRONG");} );
}
Upvotes: 47
Reputation: 5884
Actually I think there is a error in the documentation for this particular example. The method that is intended is expectThrows
public static void assertThrows(
public static <T extends Throwable> T expectThrows(
Upvotes: 1