tags:

views:

6217

answers:

5

How can use jUnit4.5 idiomatically to test that come 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 cludgy and far more in-the-spirit of jUnit for these sorts of situations.

+1  A: 

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(ex instanceof IndexOutOfBoundsException);
}
Johan
That's what you do in JUnit 3. Junit 4 does it better.
skaffman
+2  A: 

JUnit has built-in support for this, with an "expected" attribute

Mark Bessey
+15  A: 

JUnit 4 has support for this:

@Test(expected=IndexOutOfBoundsException.class)
public void testIndexOutOfBoundsException() {
    ArrayList emptyList = new ArrayList();
    Object o = emptyList.get(0);
}
skaffman
I discovered that this test doesn't fail if you get no exception. So the expected is more like an possible assumption and not a mandatory one. So in this case, your test declare that there might be thrown an IndexOutOfBoundsException, and not that the test should thrown such exception.
raisercostin
I discovered that that what i described before happened because the test wasn't marked with this annotation<code>@RunWith(value=BlockJUnit4ClassRunner.class)</code>
raisercostin
+12  A: 

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.

daveb
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'").
Rodney Gitzel
+7  A: 

If you can use JUnit 4.7, you can use the ExpectedException Rule

@RunWith(JUnit4.class)
public class FooTest {
  @Rule
  public 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

NamshubWriter