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

前端 未结 30 1937
忘掉有多难
忘掉有多难 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:01

    I recomend library assertj-core to handle exception in junit test

    In java 8, like this:

    //given
    
    //when
    Throwable throwable = catchThrowable(() -> anyService.anyMethod(object));
    
    //then
    AnyException anyException = (AnyException) throwable;
    assertThat(anyException.getMessage()).isEqualTo("........");
    assertThat(exception.getCode()).isEqualTo(".......);
    
    0 讨论(0)
  • 2020-11-21 23:02

    Java 8 solution

    If you would like a solution which:

    • Utilizes Java 8 lambdas
    • Does not depend on any JUnit magic
    • Allows you to check for multiple exceptions within a single test method
    • Checks for an exception being thrown by a specific set of lines within your test method instead of any unknown line in the entire test method
    • Yields the actual exception object that was thrown so that you can further examine it

    Here is a utility function that I wrote:

    public final <T extends Throwable> T expectException( Class<T> exceptionClass, Runnable runnable )
    {
        try
        {
            runnable.run();
        }
        catch( Throwable throwable )
        {
            if( throwable instanceof AssertionError && throwable.getCause() != null )
                throwable = throwable.getCause(); //allows "assert x != null : new IllegalArgumentException();"
            assert exceptionClass.isInstance( throwable ) : throwable; //exception of the wrong kind was thrown.
            assert throwable.getClass() == exceptionClass : throwable; //exception thrown was a subclass, but not the exact class, expected.
            @SuppressWarnings( "unchecked" )
            T result = (T)throwable;
            return result;
        }
        assert false; //expected exception was not thrown.
        return null; //to keep the compiler happy.
    }
    

    (taken from my blog)

    Use it as follows:

    @Test
    public void testThrows()
    {
        RuntimeException e = expectException( RuntimeException.class, () -> 
            {
                throw new RuntimeException( "fail!" );
            } );
        assert e.getMessage().equals( "fail!" );
    }
    
    0 讨论(0)
  • 2020-11-21 23:04

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

    • For JUnit5 and 4.13 see answer https://stackoverflow.com/a/2935935/2986984
    • If you use assertJ or google-truth, see answer https://stackoverflow.com/a/41019785/2986984

    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 :

    • JUnit Test-FAQ
    0 讨论(0)
  • 2020-11-21 23:04

    To solve the same problem I did set up a small project: http://code.google.com/p/catch-exception/

    Using this little helper you would write

    verifyException(foo, IndexOutOfBoundsException.class).doStuff();
    

    This is less verbose than the ExpectedException rule of JUnit 4.7. In comparison to the solution provided by skaffman, you can specify in which line of code you expect the exception. I hope this helps.

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

    I tried many of the methods here, but they were either complicated or didn't quite meet my requirements. In fact, one can write a helper method quite simply:

    public class ExceptionAssertions {
        public static void assertException(BlastContainer blastContainer ) {
            boolean caughtException = false;
            try {
                blastContainer.test();
            } catch( Exception e ) {
                caughtException = true;
            }
            if( !caughtException ) {
                throw new AssertionFailedError("exception expected to be thrown, but was not");
            }
        }
        public static interface BlastContainer {
            public void test() throws Exception;
        }
    }
    

    Use it like this:

    assertException(new BlastContainer() {
        @Override
        public void test() throws Exception {
            doSomethingThatShouldExceptHere();
        }
    });
    

    Zero dependencies: no need for mockito, no need powermock; and works just fine with final classes.

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

    Take for example, you want to write Junit for below mentioned code fragment

    public int divideByZeroDemo(int a,int b){
    
        return a/b;
    }
    
    public void exceptionWithMessage(String [] arr){
    
        throw new ArrayIndexOutOfBoundsException("Array is out of bound");
    }
    

    The above code is to test for some unknown exception that may occur and the below one is to assert some exception with custom message.

     @Rule
    public ExpectedException exception=ExpectedException.none();
    
    private Demo demo;
    @Before
    public void setup(){
    
        demo=new Demo();
    }
    @Test(expected=ArithmeticException.class)
    public void testIfItThrowsAnyException() {
    
        demo.divideByZeroDemo(5, 0);
    
    }
    
    @Test
    public void testExceptionWithMessage(){
    
    
        exception.expectMessage("Array is out of bound");
        exception.expect(ArrayIndexOutOfBoundsException.class);
        demo.exceptionWithMessage(new String[]{"This","is","a","demo"});
    }
    
    0 讨论(0)
提交回复
热议问题