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
You can also do this:
@Test
public void testFooThrowsIndexOutOfBoundsException() {
try {
foo.doStuff();
assert false;
} catch (IndexOutOfBoundsException e) {
assert true;
}
}
The most flexible and elegant answer for Junit 4 I found in the Mkyong blog. It has the flexibility of the try/catch
using the @Rule
annotation. I like this approach because you can read specific attributes of a customized exception.
package com.mkyong;
import com.mkyong.examples.CustomerService;
import com.mkyong.examples.exception.NameNotFoundException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.hasProperty;
public class Exception3Test {
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void testNameNotFoundException() throws NameNotFoundException {
//test specific type of exception
thrown.expect(NameNotFoundException.class);
//test message
thrown.expectMessage(is("Name is empty!"));
//test detail
thrown.expect(hasProperty("errCode")); //make sure getters n setters are defined.
thrown.expect(hasProperty("errCode", is(666)));
CustomerService cust = new CustomerService();
cust.findByName("");
}
}
In my case I always get RuntimeException from db, but messages differ. And exception need to be handled respectively. Here is how I tested it:
@Test
public void testThrowsExceptionWhenWrongSku() {
// Given
String articleSimpleSku = "999-999";
int amountOfTransactions = 1;
Exception exception = null;
// When
try {
createNInboundTransactionsForSku(amountOfTransactions, articleSimpleSku);
} catch (RuntimeException e) {
exception = e;
}
// Then
shouldValidateThrowsExceptionWithMessage(exception, MESSAGE_NON_EXISTENT_SKU);
}
private void shouldValidateThrowsExceptionWithMessage(final Exception e, final String message) {
assertNotNull(e);
assertTrue(e.getMessage().contains(message));
}
@Test(expectedException=IndexOutOfBoundsException.class)
public void testFooThrowsIndexOutOfBoundsException() throws Exception {
doThrow(IndexOutOfBoundsException.class).when(foo).doStuff();
try {
foo.doStuff();
} catch (IndexOutOfBoundsException e) {
assertEquals(IndexOutOfBoundsException .class, ex.getCause().getClass());
throw e;
}
}
Here is another way to check method thrown correct exception or not.
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
the Junit 5 User Guide.
Here is an example that verifies an exception is thrown, and uses Truth to make assertions on the exception message:
public class FooTest {
@Test
public void doStuffThrowsIndexOutOfBoundsException() {
Foo foo = new Foo();
IndexOutOfBoundsException e = assertThrows(
IndexOutOfBoundsException.class, foo::doStuff);
assertThat(e).hasMessageThat().contains("woops!");
}
}
The advantages over the approaches in the other answers are:
throws
clauseA similar method will be added to org.junit Assert
in JUnit 4.13.
IMHO, the best way to check for exceptions in JUnit is the try/catch/fail/assert pattern:
// this try block should be as small as possible,
// as you want to make sure you only catch exceptions from your code
try {
sut.doThing();
fail(); // fail if this does not throw any exception
} catch(MyException e) { // only catch the exception you expect,
// otherwise you may catch an exception for a dependency unexpectedly
// a strong assertion on the message,
// in case the exception comes from anywhere an unexpected line of code,
// especially important if your checking IllegalArgumentExceptions
assertEquals("the message I get", e.getMessage());
}
The assertTrue
might be a bit strong for some people, so assertThat(e.getMessage(), containsString("the message");
might be preferable.