How To Write Readable Unit Tests In Java

10 November 2017

There are many ways to write unit tests, here I will give you 4 tips for writing tests that will serve you well in the future.

Keep it short and simple

The smaller the test the easier it will be to maintain, both for others and for future you. Only populate the test data that actually matters.

Use assertThat

Have you ever mixed up the order of arguments to assertEquals? I often look at the javadoc to see which of them is the expected and actual value.

import static org.junit.Assert.*;

public void test() {
  assertEquals(4, addNumbers(2,2)); // correct: expected, actual
  assertEquals(addNumbers(2,2), 4); // incorrect
}

Luckily there is a more intuitive way to do this, using assertThat.

import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.is;

public void test() {
  assertThat(addNumbers(2,2), is(4));
}

As you can see, it reads more like a sentence. To negate a condition, use not.

assertThat(addNumbers(2,2), is(not(10)));

Divide

For any test longer than a few lines of code, try to split it into parts. A big wall of text is terrible to read. For example, logical groups may be formed from code that creates test data, mocks calls, verifies or asserts.

@Test
public void test_businessLogic() {
    doReturn(5).when(firstService).getA();
    doReturn(6).when(firstService).getB();
    doReturn(7).when(firstService).getC();

    doReturn(true).when(secondService).isNumber(1000000);

    BusinessResult result = businessLogic.getResult();

    assertThat(businessResult.firstThing, is("money"));
    assertThat(businessResult.secondThing, is("customer"));

    verify(emailService).send();
}

Check what actually matters

Don't verify every call the code under test makes without thinking. This will make the tests unnecessarily brittle and prone to breaking due to actually unimportant changes. Only verify what is required. The testing framework of choice can also effect how likely you are to fall into a pattern of over-verifying.

As a sidenote, don't verify a call if the code already depends on the return value of the same call. This is an example of a pointless verification:

public class Service {
    public int getA() {
        return 10;
    }
}

public class BusinessLogic {
    public Service service = new Service();

    public int getAPlus1() {
        int a = service.getA();
        return a + 1;
    }
}

@RunWith(MockitoJUnitRunner.class)
public class BusinessLogicTest {
    @Spy
    @InjectMocks
    private BusinessLogic businessLogic;

    @Mock
    private Service service;

    @Test
    public void test_getAPlus1() {
        doReturn(5).when(service).getA();

        int result = businessLogic.getAPlus1();

        assertThat(result, is(6));

        verify(service).getA(); // pointless
    }
}

Further reading

  1. JUnit wiki article on matchers
  2. Excellent article on benefits of assertThat that also has a cross reference table for the old and new way.