Single Statement Unit Tests: Making Tests More Object-Oriented

2017 October 2 @ 10:33pm by erik


In a post by Yegor Bugayenko, Single Statement Unit Tests,

“..I believe, can help us make our tests, and our production code, more object-oriented. Here it is: a test method must contain nothing but a single assert.”

He makes use of the assertThat() that is available from Hamcrest. Benefits to using assertThat() are: Reusability. Classes needed to create test assertions are reusable in other test methods and test cases. Brevity. Shorter and readable code that’s easy to understand. Readability. Using a single assert, the intent of the test will always be apparent. Immutability. No need for setters or getters if we limit use of algorithmic code in tests.

He uses an example method RandomStreamTest from OpenJDK 8, created by Brian Goetz:

@Test
public void testIntStream() {
  final long seed = System.currentTimeMillis();
  final Random r1 = new Random(seed);
  final int[] a = new int[SIZE];
  for (int i=0; i < SIZE; i++) {
    a[i] = r1.nextInt();
  }
  final Random r2 = new Random(seed);
  final int[] b = r2.ints().limit(SIZE).toArray();
  assertEquals(a, b);
}

In this example there are two parts, the algorithm which creates two arrays of integers and the assertion which compares them using assertEquals(). The author recommends modifying the code to look like this:

@Test
public void testIntStream() {
  final long seed = System.currentTimeMillis();
  assertEquals(
    new ArrayFromRandom(
      new Random(seed)
    ).toArray(SIZE),
    new Random(seed).ints().limit(SIZE).toArray()
  );
}
private static class ArrayFromRandom {
  private final Random random;
  ArrayFromRandom(Random r) {
    this.random = r;
  }
  int[] toArray(int s) {
    final int[] a = new int[s];
    for (int i=0; i < s; i++) {
      a[i] = this.random.nextInt();
    }
    return a;
  }
} 

The change is the test is that there is only one statement in the method now.

Yegor notes

"The biggest benefit we get when this principle is applied to our tests is that they become declarative and object-oriented, instead of being algorithmic, imperative, and procedural."

I chose this resource because it's an interesting way to design tests and the benefits of using assertThat() might be of use to me in the future. I think it is important to keep up on the best unit-testing practices if I want to write good code to match. I'm also interested in looking more into Hamcrest.

Using assertThat() allows you to write relatively short test cases that are clear what is being tested. Sometimes tests can become bogged down with too many assertEquals() and setters and getters. Using assertThat() allows you to simply compare two immutable objects. I plan on using this, or at least trying to implement it whenever writing tests in the future along with whatever makes writing tests more readable, understable and object oriented.

0 comments
 

by erik christensen - powered by wordpress