by BehindJava
How do you assert that a certain exception is thrown in JUnit 4 tests
In this tutorial we are going to learn about asserting a certain exception is thrown in JUnit 4 tests.
In junit, there are four ways to test exception.
junit5.x
For junit5.x, you can use assertThrows as following
@Test
public void testFooThrowsIndexOutOfBoundsException() {
Throwable exception = assertThrows(IndexOutOfBoundsException.class, () -> foo.doStuff());
assertEquals("expected messages", exception.getMessage());
}
junit4.x
For junit4.x, use the optional ‘expected’ attribute of Test annonation
@Test(expected = IndexOutOfBoundsException.class)
public void testFooThrowsIndexOutOfBoundsException() {
foo.doStuff();
}
For junit4.x, use the ExpectedException rule
public class XxxTest {
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void testFooThrowsIndexOutOfBoundsException() {
thrown.expect(IndexOutOfBoundsException.class)
//you can test the exception message like
thrown.expectMessage("expected messages");
foo.doStuff();
}
}
you also can use the classic try/catch way widely used under junit 3 framework
@Test
public void testFooThrowsIndexOutOfBoundsException() {
try {
foo.doStuff();
fail("expected exception was not occured.");
} catch(IndexOutOfBoundsException e) {
//if execution reaches here,
//it indicates this exception was occured.
//so we need not handle it.
}
}
So
- If you like junit 5, then you should like the 1st one.
- The 2nd way is used when you only want test the type of exception.
- The first and last two are used when you want test exception message further.
- If you use junit 3, then the 4th one is preferred.
For more info, you can read this document and junit5 user guide for details.
Java 8 solution
If you would like a solution which:
- Utilizes Java 8 lambdas
- Does not depend on any JUnit magic
- Allows you to check for multiple exceptions within a single test method
- Checks for an exception being thrown by a specific set of lines within your test method instead of any unknown line in the entire test method.
- Yields the actual exception object that was thrown so that you can further examine it
Here is a utility function:
public final <T extends Throwable> T expectException( Class<T> exceptionClass, Runnable runnable )
{
try
{
runnable.run();
}
catch( Throwable throwable )
{
if( throwable instanceof AssertionError && throwable.getCause() != null )
throwable = throwable.getCause(); //allows testing for "assert x != null : new IllegalArgumentException();"
assert exceptionClass.isInstance( throwable ) : throwable; //exception of the wrong kind was thrown.
assert throwable.getClass() == exceptionClass : throwable; //exception thrown was a subclass, but not the exact class, expected.
@SuppressWarnings( "unchecked" )
T result = (T)throwable;
return result;
}
assert false; //expected exception was not thrown.
return null; //to keep the compiler happy.
}
Use it as follows:
@Test
public void testMyFunction()
{
RuntimeException e = expectException( RuntimeException.class, () ->
{
myFunction();
} );
assert e.getMessage().equals( "I bj fail!" );
}
public void myFunction()
{
throw new RuntimeException( "I bj fail!" );
}