How to Unit Test Interfaces

A typical situation within a project is that you created an interface and have a number of implementations. Concluding the former idea the structure of the project follows:

.
|-- interface-impl-a
|   |-- pom.xml
|   ...
|-- interface-impl-b
|   |-- pom.xml
|   ...
|-- interface-interface
|   |-- pom.xml
|   ...
|-- interface-test
|   |-- pom.xml
|   ...
`-- pom.xml

So the question in this case is: How to test the different implementations? But is this true? No. We don't have to test the implementations we have to test the behavior of the interface for all implementations. This can be achieved by writing unit tests in both modules interface-impl-a and interface-impl-b which means in other words to copy&paste the unit test code but this is error prone and of course not effective.

The solution is to implement the unit test code in an abstract class in a separate module interface-test.

11
12
13
14
15
16
17
18
19
20
21
22
23
24
public abstract class ImplementationUnitTest {
 
    protected static IFunction function;
 
    @Test
    public void firstTest() {
        assertTrue(function.function("function1"));
    }
 
    @Test
    public void secondTest() {
        assertFalse(function.function("function"));
    }
}

The more important part is the pom.xml file which is needed in this case. We have to make sure that the test code is made available for other modules as well. So we have to define the pom like the following:

18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-jar-plugin</artifactId>
      <executions>
        <execution>
          <goals>
            <goal>test-jar</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>
 
<dependencies>
  <dependency>
    <groupId>${project.groupId}</groupId>
    <artifactId>interface-interface</artifactId>
    <version>${project.version}</version>
  </dependency>
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <scope>test</scope>
  </dependency>
</dependencies>

Based on that we can now implement the unit test for implementation-a like this:

9
10
11
12
13
14
15
16
public class ImplementationAUnitTest extends ImplementationUnitTest {
 
    @BeforeClass
    public static void beforeClass() {
        function = new ImplementationA();
    }
 
}

And for implementation-b like this:

9
10
11
12
13
14
15
16
public class ImplementationBUnitTest extends ImplementationUnitTest {
 
    @BeforeClass
    public static void beforeClass() {
        function = new ImplementationB();
    }
 
}

The only thing we need to implement is the initialization code to create an instance of the particular class.

|-- interface-impl-a
|   |-- pom.xml
|   `-- src
|       |-- main
|       |   `-- java
|       |       `-- com
|       |           `-- soebes
|       |               `-- maui
|       |                   `-- ut
|       |                       `-- inter
|       |                           `-- ImplementationA.java
|       `-- test
|           `-- java
|               `-- com
|                   `-- soebes
|                       `-- maui
|                           `-- ut
|                               `-- inter
|                                   `-- ImplementationAUnitTest.java
|-- interface-impl-b
|   |-- pom.xml
|   `-- src
|       |-- main
|       |   `-- java
|       |       `-- com
|       |           `-- soebes
|       |               `-- maui
|       |                   `-- ut
|       |                       `-- inter
|       |                           `-- ImplementationB.java
|       `-- test
|           `-- java
|               `-- com
|                   `-- soebes
|                       `-- maui
|                           `-- ut
|                               `-- inter
|                                   `-- ImplementationBUnitTest.java
|-- interface-interface
|   |-- pom.xml
|   `-- src
|       `-- main
|           `-- java
|               `-- com
|                   `-- soebes
|                       `-- maui
|                           `-- ut
|                               `-- inter
|                                   `-- IFunction.java
|-- interface-test
|   |-- pom.xml
|   `-- src
|       `-- test
|           `-- java
|               `-- com
|                   `-- soebes
|                       `-- maui
|                           `-- ut
|                               `-- inter
|                                   `-- ImplementationUnitTest.java
`-- pom.xml

You will find the complete code for this example in the examples distribution under the folder ut-examples-interface.