How can I use JUnit4 idiomatically to test that some code throws an exception?
While I can certainly do something like this:
@Test
public void testFo
JUnit framework has assertThrows()
method:
ArithmeticException exception = assertThrows(ArithmeticException.class, () ->
calculator.divide(1, 0));
assertEquals("/ by zero", exception.getMessage());
In JUnit 4 or later you can test the exceptions as follows
@Rule
public ExpectedException exceptions = ExpectedException.none();
this provides a lot of features which can be used to improve our JUnit tests.
If you see the below example I am testing 3 things on the exception.
public class MyTest {
@Rule
public ExpectedException exceptions = ExpectedException.none();
ClassUnderTest classUnderTest;
@Before
public void setUp() throws Exception {
classUnderTest = new ClassUnderTest();
}
@Test
public void testAppleisSweetAndRed() throws Exception {
exceptions.expect(Exception.class);
exceptions.expectMessage("this is the exception message");
exceptions.expectCause(Matchers.<Throwable>equalTo(exceptionCause));
classUnderTest.methodUnderTest("param1", "param2");
}
}
Edit: Now that JUnit 5 and JUnit 4.13 have been released, the best option would be to use Assertions.assertThrows() (for JUnit 5) and Assert.assertThrows() (for JUnit 4.13+). See my other answer for details.
If you haven't migrated to JUnit 5, but can use JUnit 4.7, you can use the ExpectedException Rule:
public class FooTest {
@Rule
public final ExpectedException exception = ExpectedException.none();
@Test
public void doStuffThrowsIndexOutOfBoundsException() {
Foo foo = new Foo();
exception.expect(IndexOutOfBoundsException.class);
foo.doStuff();
}
}
This is much better than @Test(expected=IndexOutOfBoundsException.class)
because the test will fail if IndexOutOfBoundsException
is thrown before foo.doStuff()
See this article for details.
How about this: catch a very general exception, make sure it makes it out of the catch block, then assert that the class of the exception is what you expect it to be. This assert will fail if a) the exception is of the wrong type (eg. if you got a Null Pointer instead) and b) the exception wasn't ever thrown.
public void testFooThrowsIndexOutOfBoundsException() {
Throwable e = null;
try {
foo.doStuff();
} catch (Throwable ex) {
e = ex;
}
assertTrue(e instanceof IndexOutOfBoundsException);
}
Just make a Matcher that can be turned off and on, like this:
public class ExceptionMatcher extends BaseMatcher<Throwable> {
private boolean active = true;
private Class<? extends Throwable> throwable;
public ExceptionMatcher(Class<? extends Throwable> throwable) {
this.throwable = throwable;
}
public void on() {
this.active = true;
}
public void off() {
this.active = false;
}
@Override
public boolean matches(Object object) {
return active && throwable.isAssignableFrom(object.getClass());
}
@Override
public void describeTo(Description description) {
description.appendText("not the covered exception type");
}
}
To use it:
add public ExpectedException exception = ExpectedException.none();
,
then:
ExceptionMatcher exMatch = new ExceptionMatcher(MyException.class);
exception.expect(exMatch);
someObject.somethingThatThrowsMyException();
exMatch.off();
With Java 8 you can create a method taking a code to check and expected exception as parameters:
private void expectException(Runnable r, Class<?> clazz) {
try {
r.run();
fail("Expected: " + clazz.getSimpleName() + " but not thrown");
} catch (Exception e) {
if (!clazz.isInstance(e)) fail("Expected: " + clazz.getSimpleName() + " but " + e.getClass().getSimpleName() + " found", e);
}
}
and then inside your test:
expectException(() -> list.sublist(0, 2).get(2), IndexOutOfBoundsException.class);
Benefits: