Categories
assert exception java junit junit4

How do you assert that a certain exception is thrown in JUnit tests?

2201

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.

5

  • 26

    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.

    – ZeroOne

    Jan 17, 2013 at 11:05

  • 5

    You can see how to exceptions test in JUnit wiki page github.com/junit-team/junit/wiki/Exception-testing

    – PhoneixS

    Feb 19, 2014 at 11:46

  • 6

    @ZeroOne – For that I would have two different tests- one for the exception and one to verify interaction with your mock.

    – tddmonkey

    Dec 25, 2014 at 17:01

  • There is a way to do this with JUnit 5, I have updated my answer below.

    May 2, 2017 at 3:05


  • Here is a nice example on how assert that an exception is Thrown it in JUnit4 and JUnit5

    Apr 12, 2021 at 18:12

2516

It depends on the JUnit version and what assert libraries you use.

The original answer for JUnit <= 4.12 was:

@Test(expected = IndexOutOfBoundsException.class)
public void testIndexOutOfBoundsException() {

    ArrayList emptyList = new ArrayList();
    Object o = emptyList.get(0);

}

Though answer https://stackoverflow.com/a/31826781/2986984 has more options for JUnit <= 4.12.

Reference :

14

  • 74

    This piece of code will not work if you expect an exception only somewhere in your code, and not a blanket like this one.

    Jun 27, 2011 at 14:50

  • 5

    @skaffman This wouldn’t work with org.junit.experimental.theories.Theory runned by org.junit.experimental.theories.Theories

    Apr 27, 2012 at 16:01


  • 84

    Roy Osherove discourages this kind of Exception testing in The art of Unit Testing, since the Exception might be anywhere inside the test and not only inside the unit under test.

    Jan 22, 2015 at 14:36


  • 22

    I disagree with @Kiview/Roy Osherove. In my view, tests should be for behaviour, not implementation. By testing that a specific method can throw an error, you are tying your tests directly to the implementation. I would argue that testing in the method shown above provides a more valuable test. The caveat I would add is that in this case I would test for a custom exception, so that I know I am getting the exception I really want.

    – nickbdyer

    May 3, 2016 at 12:22


  • 6

    Neither. I want to test the behaviour of the class. What is important, is that if I try to retrieve something that isn’t there, I get an exception. The fact that the data structure is ArrayList that responds to get() is irrelevant. If I chose in the future to move to a primitive array, I would then have to change this test implementation. The data structure should be hidden, so that the test can focus on the behaviour of the class.

    – nickbdyer

    May 3, 2016 at 16:33

1397

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.

22

  • 16

    @skaffman – If I’ve understood this correctly, it looks like the exception.expect is being applied only within one test, not the whole class.

    – bacar

    Jul 6, 2012 at 11:41

  • 5

    If the exception we expect to be thrown is an checked exception, should we add throws or try-catch or test this situation in another way?

    Jun 29, 2013 at 8:05

  • 5

    @MartinTrummer No code should run after foo.doStuff() since the exception is thrown and the method is exited. Having code after an expected exception (with the exception of closing resources in a finally) is unhelpful anyway since it should never be executed if the exception is thrown.

    Jan 17, 2014 at 15:59


  • 9

    This is the best approach. There are two advantages here, compared to skaffman’s solution. Firstly, the ExpectedException class has ways of matching the exception’s message, or even writing your own matcher that depends on the class of exception. Secondly, you can set your expectation immediately before the line of code that you expect to throw the exception – which means your test will fail if the wrong line of code throws the exception; whereas there’s no way to do that with skaffman’s solution.

    Jul 26, 2014 at 10:58

  • 5

    @MJafarMash if the exception you expect to throw is checked, then you would add that exception to the throws clause of the test method. You do the same any time you are testing a method that is declared to throw a checked exception, even if the exception isn’t triggered in the particular test case.

    May 10, 2015 at 14:38

497

Be careful using expected exception, because it only asserts that the method threw that exception, not a particular line of code in the test.

I tend to use this for testing parameter validation, because such methods are usually very simple, but more complex tests might better be served with:

try {
    methodThatShouldThrow();
    fail( "My method didn't throw when I expected it to" );
} catch (MyException expectedException) {
}

Apply judgement.

13

  • 107

    Maybe I’m old school but I still prefer this. It also gives me a place to test the exception itself: sometimes I have exceptions with getters for certain values, or I might simply look for a particular value in the message (e.g. looking for “xyz” in the message “unrecognized code ‘xyz'”).

    Oct 6, 2010 at 17:22

  • 3

    I think NamshubWriter’s approach gives you the best of both worlds.

    – Eddie

    Mar 9, 2011 at 19:21

  • 4

    Using ExpectedException you could call N exception.expect per method to test like this exception.expect(IndexOutOfBoundsException.class); foo.doStuff1(); exception.expect(IndexOutOfBoundsException.class); foo.doStuff2(); exception.expect(IndexOutOfBoundsException.class); foo.doStuff3();

    Oct 9, 2012 at 17:07


  • 10

    @user1154664 Actually, you can’t. Using ExpectedException you can only test that one method throws an exception, because when that method is called, the test will stop executing because it threw the expected exception!

    Feb 24, 2014 at 16:26

  • 2

    Your first sentence just isn’t true. When using ExpectedException, the normal thing to do is to set the expectation immediately before the line that you expect to throw the exception. That way, if an earlier line throws the exception, it won’t trigger the rule, and the test will fail.

    Jul 26, 2014 at 10:53