Writing JUnit Tests
We are testing an ArrayList<Integer> that implements this List contract:
add(e)appendseto the end of the list.remove(e)deletes the first occurrence ofeand returns true, or returns false ifeis not in the list.get(i)returns the element at indexi, and throwsIndexOutOfBoundsExceptionifi < 0ori >= 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.