JUnit: Testing Exceptions with Java 8 and AssertJ 3.0.0

AssertJ 3.0.0 release for Java 8 makes testing exceptions much easier than before. In one of my previous blog post I described how to utilize plain Java 8 to achieve this, but with AssertJ 3.0.0 much of the code I created may be removed.

Warning: this blog post contains mostly the code examples.

SUT - System Under Test

We will test exceptions thrown by the below 2 classes.

The first one:

class DummyService {
    public void someMethod() {
        throw new RuntimeException("Runtime exception occurred");
    }

    public void someOtherMethod(boolean b) {
        throw new RuntimeException("Runtime exception occurred",
                new IllegalStateException("Illegal state"));
    }
}

And the second:

class DummyService2 {
    public DummyService2() throws Exception {
        throw new Exception("Constructor exception occurred");
    }

    public DummyService2(boolean dummyParam) throws Exception {
        throw new Exception("Constructor exception occurred");
    }
}

assertThatThrownBy() examples

Note: static import of org.assertj.core.api.Assertions.assertThatThrownBy is required in order to make the below code work properly.

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

@Test
public void verifiesCauseType() {
    assertThatThrownBy(() -> new DummyService().someOtherMethod(true))
            .isInstanceOf(RuntimeException.class)
            .hasMessage("Runtime exception occurred")
            .hasCauseInstanceOf(IllegalStateException.class);
}

@Test
public void verifiesCheckedExceptionThrownByDefaultConstructor() {
    assertThatThrownBy(DummyService2::new)
            .isInstanceOf(Exception.class)
            .hasMessage("Constructor exception occurred");
}

@Test
public void verifiesCheckedExceptionThrownConstructor() {
    assertThatThrownBy(() -> new DummyService2(true))
            .isInstanceOf(Exception.class)
            .hasMessage("Constructor exception occurred");
}

The assertions presented comes from AbstractThrowableAssert and there are much more of them for you to use!

No exception thrown!

The below test will fail as no exception is thrown:

@Test
public void failsWhenNoExceptionIsThrown() {    
    assertThatThrownBy(() -> System.out.println());
}

The message is:

java.lang.AssertionError: Expecting code to raise a throwable.

AAA Style

If you wish to distinguish act and assert phases of the test for improving readability, it is also possible:

@Test
public void aaaStyle() {
    // arrange
    DummyService dummyService = new DummyService();

    // act
    Throwable throwable = catchThrowable(dummyService::someMethod);

    // assert
    assertThat(throwable)
            .isNotNull()
            .hasMessage("Runtime exception occurred");
}

References

  • Source code for this article is available on GitHub (have a look at com.github.kolorobot.assertj.exceptions package)
  • AssertJ 3.0.0 for Java 8 release

Popular posts from this blog

Parameterized tests in JavaScript with Jest

macOS: Insert current date shortcut with `Shortcuts.app`