How do I assert my exception message with JUnit Test annotation?

前端 未结 12 2002
广开言路
广开言路 2020-12-12 08:53

I have written a few JUnit tests with @Test annotation. If my test method throws a checked exception and if I want to assert the message along with the exceptio

相关标签:
12条回答
  • 2020-12-12 09:18
    @Test (expectedExceptions = ValidationException.class, expectedExceptionsMessageRegExp = "This is not allowed")
    public void testInvalidValidation() throws Exception{
         //test code
    }
    
    0 讨论(0)
  • 2020-12-12 09:19

    You could use the @Rule annotation with ExpectedException, like this:

    @Rule
    public ExpectedException expectedEx = ExpectedException.none();
    
    @Test
    public void shouldThrowRuntimeExceptionWhenEmployeeIDisNull() throws Exception {
        expectedEx.expect(RuntimeException.class);
        expectedEx.expectMessage("Employee ID is null");
    
        // do something that should throw the exception...
        System.out.println("=======Starting Exception process=======");
        throw new NullPointerException("Employee ID is null");
    }
    

    Note that the example in the ExpectedException docs is (currently) wrong - there's no public constructor, so you have to use ExpectedException.none().

    0 讨论(0)
  • 2020-12-12 09:22

    I would prefer AssertJ for this.

            assertThatExceptionOfType(ExpectedException.class)
            .isThrownBy(() -> {
                // method call
            }).withMessage("My message");
    
    0 讨论(0)
  • 2020-12-12 09:23

    Raystorm had a good answer. I'm not a big fan of Rules either. I do something similar, except that I create the following utility class to help readability and usability, which is one of the big plus'es of annotations in the first place.

    Add this utility class:

    import org.junit.Assert;
    
    public abstract class ExpectedRuntimeExceptionAsserter {
    
        private String expectedExceptionMessage;
    
        public ExpectedRuntimeExceptionAsserter(String expectedExceptionMessage) {
            this.expectedExceptionMessage = expectedExceptionMessage;
        }
    
        public final void run(){
            try{
                expectException();
                Assert.fail(String.format("Expected a RuntimeException '%s'", expectedExceptionMessage));
            } catch (RuntimeException e){
                Assert.assertEquals("RuntimeException caught, but unexpected message", expectedExceptionMessage, e.getMessage());
            }
        }
    
        protected abstract void expectException();
    
    }
    

    Then for my unit test, all I need is this code:

    @Test
    public void verifyAnonymousUserCantAccessPrivilegedResourceTest(){
        new ExpectedRuntimeExceptionAsserter("anonymous user can't access privileged resource"){
            @Override
            protected void expectException() {
                throw new RuntimeException("anonymous user can't access privileged resource");
            }
        }.run(); //passes test; expected exception is caught, and this @Test returns normally as "Passed"
    }
    
    0 讨论(0)
  • 2020-12-12 09:25

    I never liked the way of asserting exceptions with Junit. If I use the "expected" in the annotation, seems from my point of view we're violating the "given, when, then" pattern because the "then" is placed at the top of the test definition.

    Also, if we use "@Rule", we have to deal with so much boilerplate code. So, if you can install new libraries for your tests, I'd suggest to have a look to the AssertJ (that library now comes with SpringBoot)

    Then a test which is not violating the "given/when/then" principles, and it is done using AssertJ to verify:

    1 - The exception is what we're expecting. 2 - It has also an expected message

    Will look like this:

     @Test
    void should_throwIllegalUse_when_idNotGiven() {
    
        //when
        final Throwable raisedException = catchThrowable(() -> getUserDAO.byId(null));
    
        //then
        assertThat(raisedException).isInstanceOf(IllegalArgumentException.class)
                .hasMessageContaining("Id to fetch is mandatory");
    }
    
    0 讨论(0)
  • 2020-12-12 09:28

    In JUnit 4.13 you can do:

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

    This also works in JUnit 5 but with different imports:

    import static org.junit.jupiter.api.Assertions.assertEquals;
    import static org.junit.jupiter.api.Assertions.assertThrows;
    
    ...
    
    0 讨论(0)
提交回复
热议问题