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

ID : 393

viewed : 349

Tags : javaexceptionjunitjunit4assertjava





Top 5 Answer for java - How do you assert that a certain exception is thrown in JUnit 4 tests?

vote vote

90

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 :

vote vote

80

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.

vote vote

74

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.

vote vote

66

As answered before, there are many ways of dealing with exceptions in JUnit. But with Java 8 there is another one: using Lambda Expressions. With Lambda Expressions we can achieve a syntax like this:

@Test public void verifiesTypeAndMessage() {     assertThrown(new DummyService()::someMethod)             .isInstanceOf(RuntimeException.class)             .hasMessage("Runtime exception occurred")             .hasMessageStartingWith("Runtime")             .hasMessageEndingWith("occurred")             .hasMessageContaining("exception")             .hasNoCause(); } 

assertThrown accepts a functional interface, whose instances can be created with lambda expressions, method references, or constructor references. assertThrown accepting that interface will expect and be ready to handle an exception.

This is relatively simple yet powerful technique.

Have a look at this blog post describing this technique: http://blog.codeleak.pl/2014/07/junit-testing-exception-with-java-8-and-lambda-expressions.html

The source code can be found here: https://github.com/kolorobot/unit-testing-demo/tree/master/src/test/java/com/github/kolorobot/exceptions/java8

Disclosure: I am the author of the blog and the project.

vote vote

60

in junit, there are four ways to test exception.

junit5.x

  • for junit5.x, you can use assertThrows as following

    @Test public void testFooThrowsIndexOutOfBoundsException() {     Throwable exception = assertThrows(IndexOutOfBoundsException.class, () -> foo.doStuff());     assertEquals("expected messages", exception.getMessage()); } 

junit4.x

  • for junit4.x, use the optional 'expected' attribute of Test annonation

    @Test(expected = IndexOutOfBoundsException.class) public void testFooThrowsIndexOutOfBoundsException() {     foo.doStuff(); } 
  • for junit4.x, use the ExpectedException rule

    public class XxxTest {     @Rule     public ExpectedException thrown = ExpectedException.none();      @Test     public void testFooThrowsIndexOutOfBoundsException() {         thrown.expect(IndexOutOfBoundsException.class)         //you can test the exception message like         thrown.expectMessage("expected messages");         foo.doStuff();     } } 
  • you also can use the classic try/catch way widely used under junit 3 framework

    @Test public void testFooThrowsIndexOutOfBoundsException() {     try {         foo.doStuff();         fail("expected exception was not occured.");     } catch(IndexOutOfBoundsException e) {         //if execution reaches here,          //it indicates this exception was occured.         //so we need not handle it.     } } 
  • so

    • if you like junit 5, then you should like the 1st one
    • the 2nd way is used when you only want test the type of exception
    • the first and last two are used when you want test exception message further
    • if you use junit 3, then the 4th one is preferred
  • for more info, you can read this document and junit5 user guide for details.

Top 3 video Explaining java - How do you assert that a certain exception is thrown in JUnit 4 tests?







Related QUESTION?