2340

How can I use JUnit idiomatically to test that some code throws an exception?

While I can certainly do something like this:

@Test public void testFooThrowsIndexOutOfBoundsException() { boolean thrown = false; try { foo.doStuff(); } catch (IndexOutOfBoundsException e) { thrown = true; } assertTrue(thrown); } 

I recall that there is an annotation or an Assert.xyz or something that is far less kludgy and far more in-the-spirit of JUnit for these sorts of situations.

4
  • 28
    The problem with any other approach but this is that they invariably end the test once the exception has been thrown. I, on the other hand, often still want to call org.mockito.Mockito.verify with various parameters to make sure that certain things happened (such that a logger service was called with the correct parameters) before the exception was thrown. Commented Jan 17, 2013 at 11:05
  • 6
    You can see how to exceptions test in JUnit wiki page github.com/junit-team/junit/wiki/Exception-testing Commented Feb 19, 2014 at 11:46
  • 7
    @ZeroOne - For that I would have two different tests- one for the exception and one to verify interaction with your mock. Commented Dec 25, 2014 at 17:01
  • Here is a nice example on how assert that an exception is Thrown it in JUnit4 and JUnit5 Commented Apr 12, 2021 at 18:12

35 Answers 35

1
2
1
 @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.

Sign up to request clarification or add additional context in comments.

Comments

0

My solution using Java 8 lambdas:

public static <T extends Throwable> T assertThrows(Class<T> expected, ThrowingRunnable action) throws Throwable { try { action.run(); Assert.fail("Did not throw expected " + expected.getSimpleName()); return null; // never actually } catch (Throwable actual) { if (!expected.isAssignableFrom(actual.getClass())) { // runtime '!(actual instanceof expected)' System.err.println("Threw " + actual.getClass().getSimpleName() + ", which is not a subtype of expected " + expected.getSimpleName()); throw actual; // throw the unexpected Throwable for maximum transparency } else { return (T) actual; // return the expected Throwable for further examination } } } 

You have to define a FunctionalInterface, because Runnable doesn't declare the required throws.

@FunctionalInterface public interface ThrowingRunnable { void run() throws Throwable; } 

The method can be used as follows:

class CustomException extends Exception { public final String message; public CustomException(final String message) { this.message = message;} } CustomException e = assertThrows(CustomException.class, () -> { throw new CustomException("Lorem Ipsum"); }); assertEquals("Lorem Ipsum", e.message); 

Comments

0

There are two ways of writing test case

  1. Annotate the test with the exception which is thrown by the method. Something like this @Test(expected = IndexOutOfBoundsException.class)
  2. You can simply catch the exception in the test class using the try catch block and assert on the message that is thrown from the method in test class.

    try{ } catch(exception to be thrown from method e) { assertEquals("message", e.getmessage()); } 

I hope this answers your query Happy learning...

Comments

-1

I wanted to comment with my solution to this problem, which avoided needing any of the exception related JUnit code.

I used assertTrue(boolean) combined with try/catch to look for my expected exception to be thrown. Here's an example:

public void testConstructor() { boolean expectedExceptionThrown; try { // Call constructor with bad arguments double a = 1; double b = 2; double c = a + b; // In my example, this is an invalid option for c new Triangle(a, b, c); expectedExceptionThrown = false; // because it successfully constructed the object } catch(IllegalArgumentException e) { expectedExceptionThrown = true; // because I'm in this catch block } catch(Exception e) { expectedExceptionThrown = false; // because it threw an exception but not the one expected } assertTrue(expectedExceptionThrown); } 

1 Comment

The second catch would swallow the stack trace if some other exception is thrown, losing useful information
-4
try { my method(); fail( "This method must thrwo" ); } catch (Exception ex) { assertThat(ex.getMessage()).isEqual(myErrormsg); } 

7 Comments

You are answering on a 10 year old question, please expand your answer, why you think it provides something new, that the accepted answer does not cover. Also always try to tell something about your code and provide documentation or explanation.
This is basically a duplicate of this 10 year old answer (except for the check for the error message).
It's not always the same person who complains about your question/answer and downvots you (like in this case, I didn't, but please take my words and expand your answer).
I am not sure if the test depending just on the error message is a good practice.
Yeah it is a good practice and useful when you have many error messages, so that you make sure that this specific one will be thrown (many possible exceptions)
|
1
2

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.