Published on

How to Test Java 8 Interface Default Methods

Authors

Java 8 introduced the really useful feature of allowing you to define default method implementations in interfaces. This makes life much easier as you would otherwise (in older versions of Java) have to make an abstract class to hold this default type of behaviour which means you now loose the ability to extend any other classes. So I for example have the following:

public interface MyAwesomeInterface {

    void doCoolStuff();

    String doEvenCoolerStuff();

    default String toTitleCase(String textToMakeTitleCase) {
        return textToMakeTitleCase.substring(0, 1).toUpperCase() + textToMakeTitleCase.substring(1).toLowerCase();

    }
}

Now where it can get a bit tricky is how do you test this default method without testing something that implements this interface in your production code? You ideally want to avoid testing this via real implementations for 2 reasons:

  1. The real implementation may override the default method (you would need to test this separately then anyway)
  2. You may decide to stop implementing the interface in this implementation or you simply decide to delete the class

The easiest way to work around these issues is make a test implementation of this class and test the default method on this test implementation. This test implementation does nothing else other than implement the interface without fleshing out the abstract methods. So we end up with something like the following:

import org.hamcrest.CoreMatchers.`is`
import org.hamcrest.CoreMatchers.equalTo
import org.hamcrest.MatcherAssert.assertThat
import org.junit.jupiter.api.Test

internal class MyAwesomeInterfaceTest {

    private inner class MyAwesomeTestImpl : MyAwesomeInterface {
        override fun doCoolStuff() {
            throw RuntimeException("Not implemented for tests")
        }

        override fun doEvenCoolerStuff(): String {
            throw RuntimeException("Not implemented for tests")
        }
    }

    @Test
    fun toTitleCase_allLowerCase_returnsTitleCaseString() {
        val awesome = MyAwesomeTestImpl()
        assertThat(awesome.toTitleCase("john"), `is`(equalTo("John")))
    }
}