From Testing a Class to Testing a Contract

None of our tests mention an array or linked list. They are written entirely in terms of what a List promises: size, add, get, and the IndexOutOfBoundsException on an out-of-range index.

This is intentional. We are writing the tests against the contract of List, not a particular implementation of it.

So what will happen if we write the tests against the contract for each implementation? We will end up with two copies of the same suite of tests, something like this:

public class ArrayListTest {
  private List<Integer> list;

  @BeforeEach
  public void setup() {
    list = new ArrayList<>();
  }

  @Test
  public void newListIsEmpty() { ... }

  @Test
  public void addThenGetReturnsElement() { ... }

  @Test
  public void getBelowRangeThrows() { ... }
}

public class LinkedListTest {
  private List<Integer> list;

  @BeforeEach
  public void setup() {
    list = new LinkedList<>();  // the only line that differs
  }

  @Test
  public void newListIsEmpty() { ... }           // identical

  @Test
  public void addThenGetReturnsElement() { ... }  // identical

  @Test
  public void getBelowRangeThrows() { ... }       // identical
}

Only one line differs: the implementation we construct in setup(). This is code duplication. We can remove it by using inheritance.