Saying the Setup Once

Look at the two tests we have so far, side by side:

@Test
public void newListIsEmpty() {
  List<Integer> list = new ArrayList<>();
  assertEquals(0, list.size());
}

@Test
public void addThenGetReturnsElement() {
  List<Integer> list = new ArrayList<>();
  list.add(42);
  assertEquals(42, list.get(0));
}

Both begin with building a fresh list. Every test we add will probably begin the same way. That is code duplication. The usual fix is to move the construction (and any other shared setup) into a method and then call it from each test.

public class ArrayListTest {

  private List<Integer> list;

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

  @Test
  public void newListIsEmpty() {
    setup();
    assertEquals(0, list.size());
  }

  @Test
  public void addThenGetReturnsElement() {
    setup();
    list.add(42);
    assertEquals(42, list.get(0));
  }
}

Notice that we made list a field so both tests can use it. The setup() method is called at the start of each test, so the list is fresh and empty for each test.

I replaced one line, List<Integer> list = new ArrayList<>();, with another, setup();. The benefit is that the construction is now written in one place. If we later decide to change the implementation of List we are testing, we only have to change it in setup(). Also, the setup may include more than just constructing the list.

The @BeforeEach Annotation

The first step in each test is to call setup(). JUnit has a built-in way to do that automatically. We can mark the setup() method with the @BeforeEach annotation, and JUnit will call it for us before every test.

import org.junit.jupiter.api.BeforeEach;

public class ArrayListTest {

  private List<Integer> list;

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

  @Test
  public void newListIsEmpty() {
    assertEquals(0, list.size());
  }

  @Test
  public void addThenGetReturnsElement() {
    list.add(42);
    assertEquals(42, list.get(0));
  }
}

The setup line is gone from both tests. Each test now begins with the operation it is testing. Note the setup method here only creates the fresh, empty list. Each test still arranges its own data, the specific elements it needs, in its own body.

JUnit runs setup() again before every test, so each test gets its own new, empty list. This keeps the tests isolated from each other. If one test changes the list, it does not affect the other tests. It also removes ordering dependencies between tests. Each test can be run in any order, and they will all work with a fresh list.

JUnit also has a @BeforeAll that runs only once for the whole class. We should not use it here. If we used @BeforeAll, the list would be created once and shared by all tests. If one test added an element, the next test would see that element, and the tests would not be isolated. In other situations, @BeforeAll is useful for expensive setup that can be shared. For example, if you are testing a database, you might want to create the database once and add some test data to it, and then run all the tests against that same database.