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

前端 未结 30 1988
忘掉有多难
忘掉有多难 2020-11-21 22:23

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         


        
相关标签:
30条回答
  • 2020-11-21 23:15

    BDD Style Solution: JUnit 4 + Catch Exception + AssertJ

    import static com.googlecode.catchexception.apis.BDDCatchException.*;
    
    @Test
    public void testFooThrowsIndexOutOfBoundsException() {
    
        when(() -> foo.doStuff());
    
        then(caughtException()).isInstanceOf(IndexOutOfBoundsException.class);
    
    }
    

    Dependencies

    eu.codearte.catch-exception:catch-exception:2.0
    
    0 讨论(0)
  • 2020-11-21 23:15

    Update: JUnit5 has an improvement for exceptions testing: assertThrows.

    The following example is from: Junit 5 User Guide

     @Test
    void exceptionTesting() {
        Throwable exception = assertThrows(IllegalArgumentException.class, () -> 
        {
            throw new IllegalArgumentException("a message");
        });
        assertEquals("a message", exception.getMessage());
    }
    

    Original answer using JUnit 4.

    There are several ways to test that an exception is thrown. I have also discussed the below options in my post How to write great unit tests with JUnit

    Set the expected parameter @Test(expected = FileNotFoundException.class).

    @Test(expected = FileNotFoundException.class) 
    public void testReadFile() { 
        myClass.readFile("test.txt");
    }
    

    Using try catch

    public void testReadFile() { 
        try {
            myClass.readFile("test.txt");
            fail("Expected a FileNotFoundException to be thrown");
        } catch (FileNotFoundException e) {
            assertThat(e.getMessage(), is("The file test.txt does not exist!"));
        }
         
    }
    

    Testing with ExpectedException Rule.

    @Rule
    public ExpectedException thrown = ExpectedException.none();
    
    @Test
    public void testReadFile() throws FileNotFoundException {
        
        thrown.expect(FileNotFoundException.class);
        thrown.expectMessage(startsWith("The file test.txt"));
        myClass.readFile("test.txt");
    }
    

    You could read more about exceptions testing in JUnit4 wiki for Exception testing and bad.robot - Expecting Exceptions JUnit Rule.

    0 讨论(0)
  • 2020-11-21 23:15

    JUnit 5 Solution

    @Test
    void testFooThrowsIndexOutOfBoundsException() {    
      Throwable exception = expectThrows( IndexOutOfBoundsException.class, foo::doStuff );
    
      assertEquals( "some message", exception.getMessage() );
    }
    

    More Infos about JUnit 5 on http://junit.org/junit5/docs/current/user-guide/#writing-tests-assertions

    0 讨论(0)
  • 2020-11-21 23:16

    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.

    0 讨论(0)
  • 2020-11-21 23:18

    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.

    0 讨论(0)
  • 2020-11-21 23:19

    Junit4 solution with Java8 is to use this function:

    public Throwable assertThrows(Class<? extends Throwable> expectedException, java.util.concurrent.Callable<?> funky) {
        try {
            funky.call();
        } catch (Throwable e) {
            if (expectedException.isInstance(e)) {
                return e;
            }
            throw new AssertionError(
                    String.format("Expected [%s] to be thrown, but was [%s]", expectedException, e));
        }
        throw new AssertionError(
                String.format("Expected [%s] to be thrown, but nothing was thrown.", expectedException));
    }
    

    Usage is then:

        assertThrows(ValidationException.class,
                () -> finalObject.checkSomething(null));
    

    Note that the only limitation is to use a final object reference in lambda expression. This solution allows to continue test assertions instead of expecting thowable at method level using @Test(expected = IndexOutOfBoundsException.class) solution.

    0 讨论(0)
提交回复
热议问题