2 min read

How to Write Simple Unit Tests

A unit test should follow the same flow, no matter what the test is and test one thing.
How to Write Simple Unit Tests

Simple Unit Tests

In this article, JUnit will be the testing framework that is used for examples.

Simple unit tests will test only one thing and follow the same three steps in the following order.

Setup

Define the data that the test is going to be using. Some unit tests may not require test data, and this step would be skipped.

Exercise

This is calling the method that is being tested.

Assert

One or more asserts that verify the result of the method being exercised is as expected. If you are mocking in your tests, you may have verifies and asserts in this step.

Using These Steps

An example of using these three steps would be:

public final class UserDaoTest {

    @Test
    public void returnsUserWhenFoundById() {
        // Setup
        final User user = create();

        // Exercise
        final User result = userDao.findById(user.id());

        // Assert
        assertThat(result.id(), is(user.id());
    }
}

Testing Only One Thing

Tests should test only one thing but not be so simple that you complicate the test class with too many little tests. If you had a method that loads a user from the database, there are two outcomes for this method. One is it returns a user, and the other is it throws an exception if the user isn't found. For this, you would want two difference tests.

public final class UserDaoTest {

    @Test
    public void returnsUserWhenFoundById() {
        // Setup
        final User user = create();

        // Exercise
        final User result = userDao.findById(user.id());

        // Assert
        assertThat(result.id(), is(user.id());
    }

    @Test
    public void throwsExceptionWhenNotFoundById() {
        // Setup
        final long missingUserId = 0L;
        
        // Exercise the method and assert
        assertThrows(
            NoResultFoundException.class,
            () -> userDao.findById(missingUserId);
        );
    }
}

Don't Oversimplify

You have an enumeration, and the ordinal value is saved to the database. Changing the ordinal would break existing data and load the wrong enumeration. You would want to have tests that fail if these ordinal values change. You could break each one of these up into individual tests, but a simpler way in this case would be to combine them all in one test.

public enum Color {
    GREEN,
    YELLOW,
    BLUE
}

public final class ColorTest {

    @Test
    public void ensureOrdinalsNeverChange() {
        // Exercise/Assert
        assertThat(Color.GREEN.ordinal(), is(0));
        assertThat(Color.YELLOW.ordinal(), is(1));
        assertThat(Color.BLUE.ordinal(), is(2));
    }
}

Conclusion

Keeping tests simple requires each test to test only one thing. Each test should follow the same three steps without repeating them.