Home » Java » Core Java » JUnit: testing exception with Java 8 and Lambda Expressions

About Rafal Borowiec

Rafal is an IT specialist with about 8 years of commercial experience, specializing in software testing and quality assurance, software development, project management and team leadership. He is currently holding a position of a Team Leader at Goyello where he is mainly responsible for building and managing teams of professional developers and testers. He is also responsible for maintaining relations with customers and acquiring new ones, mainly through consultancy. He believes in Agile project management and he is a big fan of technology, especially Java related (but not limited too). He likes sharing knowledge about software development and practices, through his blog (blog.codeleak.pl) and Twitter (@kolorobot) but also on internal and external events like conferences or workshops.

JUnit: testing exception with Java 8 and Lambda Expressions

In JUnit there are many ways of testing exceptions in test code, including try-catch idiom, JUnit @Rule, with catch-exception library. As of Java 8 we have another way of dealing with exceptions: with lambda expressions. In this short blog post I will demonstrate a simple example how one can utilize the power of Java 8 and lambda expressions to test exceptions in JUnit.

Note: The motivation for writing this blog post was the message published on the catch-exception project page:

 
 
 

Java 8’s lambda expressions will make catch-exception redundant. Therefore, this project won’t be maintained any longer

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() {
        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");
    }
}

Desired Syntax

My goal was to achieve syntax close to the one I had with catch-exception library:

package com.github.kolorobot.exceptions.java8;

import org.junit.Test;
import static com.github.kolorobot.exceptions.java8.ThrowableAssertion.assertThrown;

public class Java8ExceptionsTest {

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

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

    @Test
    public void verifiesCheckedExceptionThrownByDefaultConstructor() {
        assertThrown(DummyService2::new) // constructor reference
                // assertions
                .isInstanceOf(Exception.class)
                .hasMessage("Constructor exception occurred");
    }

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

    @Test(expected = ExceptionNotThrownAssertionError.class) // making test pass
    public void failsWhenNoExceptionIsThrown() {
        // expected exception not thrown
        assertThrown(() -> System.out.println());
    }
}

Note: The advantage over catch-exception is that we will be able to test constructors that throw exceptions.

Creating the ‘library’

Syntatic sugar

assertThrown is a static factory method creating a new instance of ThrowableAssertion with a reference to caught exception.

package com.github.kolorobot.exceptions.java8;

public class ThrowableAssertion {
    public static ThrowableAssertion assertThrown(ExceptionThrower exceptionThrower) {
        try {
            exceptionThrower.throwException();
        } catch (Throwable caught) {
            return new ThrowableAssertion(caught);
        }
        throw new ExceptionNotThrownAssertionError();
    }

    // other methods omitted for now
}

The ExceptionThrower is a @FunctionalInterface which instances can be created with lambda expressions, method references, or constructor references. assertThrown accepting ExceptionThrower will expect and be ready to handle an exception.

@FunctionalInterface
public interface ExceptionThrower {
    void throwException() throws Throwable;
}

Assertions

To finish up, we need to create some assertions so we can verify our expactions in test code regarding teste exceptions. In fact, ThrowableAssertion is a kind of custom assertion providing us a way to fluently verify the caught exception. In the below code I used Hamcrest matchers to create assertions. The full source of ThrowableAssertion class:

package com.github.kolorobot.exceptions.java8;

import org.hamcrest.Matchers;
import org.junit.Assert;

public class ThrowableAssertion {

    public static ThrowableAssertion assertThrown(ExceptionThrower exceptionThrower) {
        try {
            exceptionThrower.throwException();
        } catch (Throwable caught) {
            return new ThrowableAssertion(caught);
        }
        throw new ExceptionNotThrownAssertionError();
    }

    private final Throwable caught;

    public ThrowableAssertion(Throwable caught) {
        this.caught = caught;
    }

    public ThrowableAssertion isInstanceOf(Class<? extends Throwable> exceptionClass) {
        Assert.assertThat(caught, Matchers.isA((Class<Throwable>) exceptionClass));
        return this;
    }

    public ThrowableAssertion hasMessage(String expectedMessage) {
        Assert.assertThat(caught.getMessage(), Matchers.equalTo(expectedMessage));
        return this;
    }

    public ThrowableAssertion hasNoCause() {
        Assert.assertThat(caught.getCause(), Matchers.nullValue());
        return this;
    }

    public ThrowableAssertion hasCauseInstanceOf(Class<? extends Throwable> exceptionClass) {
        Assert.assertThat(caught.getCause(), Matchers.notNullValue());
        Assert.assertThat(caught.getCause(), Matchers.isA((Class<Throwable>) exceptionClass));
        return this;
    }
}

AssertJ Implementation

In case you use AssertJ library, you can easily create AssertJ version of ThrowableAssertion utilizing org.assertj.core.api.ThrowableAssert that provides many useful assertions out-of-the-box. The implementation of that class is even simpler than with Hamcrestpresented above.

package com.github.kolorobot.exceptions.java8;

import org.assertj.core.api.Assertions;
import org.assertj.core.api.ThrowableAssert;

public class AssertJThrowableAssert {
    public static ThrowableAssert assertThrown(ExceptionThrower exceptionThrower) {
        try {
            exceptionThrower.throwException();
        } catch (Throwable throwable) {
            return Assertions.assertThat(throwable);
        }
        throw new ExceptionNotThrownAssertionError();
    }
}

An example test with AssertJ:

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

Summary

With just couple of lines of code, we built quite cool code helping us in testing exceptions in JUnit without any additional library. And this was just a start. Harness the power of Java 8 and lambda expressions!

Resources

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you our best selling eBooks for FREE!

1. JPA Mini Book

2. JVM Troubleshooting Guide

3. JUnit Tutorial for Unit Testing

4. Java Annotations Tutorial

5. Java Interview Questions

6. Spring Interview Questions

7. Android UI Design

and many more ....

Leave a Reply

Your email address will not be published. Required fields are marked *

*


4 + = nine

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Do you want to know how to develop your skillset and become a ...

Subscribe to our newsletter to start Rocking right now!

To get you started we give you our best selling eBooks for FREE!
Get ready to Rock!
To download the books, please verify your email address by following the instructions found on the email we just sent you.

THANK YOU!

Close