Well, it passed yesterday

Consider the following innocent-looking unit test:

public class SomeTest {
    private static final Random RND = new Random();
    private Long id1 = RND.nextLong();
    private Long id2 = RND.nextLong();

    private SomeDao dao = new SomeDao();

    @Test
    public void whenWeSaveOneTheOtherCannotBeFound() {
        // when we save something under id 1
        dao.save(id1, "Hello world");

        // then the second id doesn't have a hit
        assertThat(dao.get(id2)).isEmpty();

        // but the first does
        assertThat(dao.get(id1)).hasValue("Hello world");
    }
}

Seems reasonable enough. We don’t really care for the test values so long as they are available to us and different from each other…

… are they different from each other?

Screen Shot 2018-09-18 at 08.41.59

(with thanks to Dilbert)

It turns out that in some situations the above code will generate two identifiers that are the same. Then the accompanying test will fail. Furthermore, if the test isn’t written in such a way as it outputs failing values, there would be no way to work out what the input happened to be when it failed that time in order to reproduce it.

As a rule, therefore, AVOID RANDOM NUMBERS IN ALL TESTS!!!

This is a real shame as there are tools out there like Java Faker which produce handy inputs for things. That said, the above rule is relaxed if there’s really no impact of the values on the test. Similarly, use of UUID.randomUUID can probably be trusted to give a unique value every time.

Two ways to ameliorate things

You can seed Random with the same number every time. This will make your tests deterministic, in that the same numbers will be fed in every time. This means if it works today, it will keep on working tomorrow… unless you change the order of tests and suddenly the randomness starts hitting colliding values.

You can collect a series of unique values into a list and use Collections.shuffle or similar to order the list pseudo-randomly. This will suffer from a certain amount of non-repeatability, but will at least guarantee no collisions.

Overall

Don’t use randomness if you can avoid it. Use test data factories to make discrete unique values that you have control of. If in doubt, add ways of displaying the test data.

For more information about testing in Java, please checkout my online tutorial at Udemy.

Advertisements

One comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s