Writing JUnit Tests

We are testing an ArrayList<Integer> that implements this List contract:

  • add(e) appends e to the end of the list.
  • remove(e) deletes the first occurrence of e and returns true, or returns false if e is not in the list.
  • get(i) returns the element at index i, and throws IndexOutOfBoundsException if i < 0 or i >= size().
  • size() returns the number of elements.

The test class is:

public class ArrayListTest {

  private List<Integer> list;

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

  // tests go here
}
Solution

setup() runs before every test, so each test starts with a fresh empty list. If tests shared one list, a test that added elements would change what the next test sees, and a failure could be caused by a different test that ran earlier.

Solution
@Test
public void removeOnlyElementLeavesListEmpty() {
  list.add(55);
  list.remove(55);
  assertEquals(0, list.size());
}
Solution
@Test
public void getOnEmptyListThrows() {
  try {
    list.get(0);
    fail("expected IndexOutOfBoundsException on an empty list");
  } catch (IndexOutOfBoundsException e) {
    return;
  }
}
Solution

It checks several behaviors in one test, so a failure cannot say which one broke. Its name also says which method it calls, not which scenario it checks. Split it into separate tests, each named after its scenario, such as removeReturnsTrueForPresentElement, removeShrinksSize, and removeKeepsRemainingElementsInOrder.

Solution

get is specified to throw that particular exception. With catch (Exception e), a buggy get that threw a NullPointerException would be caught and the test would pass. With the specific type, the wrong exception escapes the test and fails it.