Thursday, 23 March 2017

AssertJ vs. Hamcrest

I recently came across a piece of code that used a Stack1. The Stack seems to inherit from Vector. The JavaDoc indicated (and so did my IDE, I think) that I should be using the Deque2 interface instead. To be precise:
“A more complete and consistent set of LIFO stack operations is provided by the Deque interface and its implementations, which should be used in preference to this class.”
Dequeue basically seems to be a specialized Queue3, that supports element insertion and removal at both ends4.

In order to get to grips with Deque, I decided to write some simple tests. These are JUnit Tests (version 4.12) and in one I used Hamcrest5 and in the other I went for AssertJ6.

Let's see what happens.

A simple compare

Hamcrest:
assertThat(actual, equalTo(testdata2));
AssertJ:
assertThat(actual).isEqualTo(testdata2);

Collections

Hamcrest:
assertThat(transmittedTestdata, hasSize(2));
AssertJ:
assertThat(transmittedTestdata).size().isEqualTo(2);

Null Values

Hamcrest:
assertThat(actual, not(nullValue()));
AssertJ:
assertThat(actual).isNotNull();

Exceptions

Hamcrest:
@Test(expected = NoSuchElementException.class)
public void testEmptyDequeueException()
{
  Deque<Testdata> transmittedTestdata = new ConcurrentLinkedDeque<>();
  Testdata pop = transmittedTestdata.pop();
}
AssertJ:
assertThatThrownBy(transmittedTestdata::pop).isInstanceOf(NoSuchElementException.class);

Imports

A comparison between the required imports of Hamcrest and Assertj is interesting:
Hamcrest:
import java.util.Deque;
import java.util.NoSuchElementException;
import java.util.concurrent.ConcurrentLinkedDeque;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.hasSize;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
AssertJ:
import java.util.Deque;
import java.util.NoSuchElementException;
import java.util.concurrent.ConcurrentLinkedDeque;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

Notes

  • I really like the AssertJ fluent API. It feels more natural to me than the Hamcrest one.
  • It is way easier to find the appropriate matchers in AssertJ. I get the full benefit of my IDE code completion.
  • Adding the appropriate import is way easier. Using Hamcrest, I always get a choice of five different imports for the same matcher.
  • I need fewer imports anyways.
So far, I like AssertJ a lot.

I need to work with AssertJ a lot more, to see some of the interesting stuff.

References

[1] Java 7 JavaDoc - Stack
https://docs.oracle.com/javase/7/docs/api/java/util/Stack.html
[2] Java 7 JavaDoc - Deque
https://docs.oracle.com/javase/7/docs/api/java/util/Deque.html
[3] Java 7 JavaDoc - Queue
https://docs.oracle.com/javase/7/docs/api/java/util/Queue.html
[4] Wikipedia - Double-ended queue
https://en.wikipedia.org/wiki/Double-ended_queue
[5] Hamcrest - Matchers that can be combined to create flexible expressions of intent
http://hamcrest.org/
[6] AssertJ - Quick start
http://joel-costigliola.github.io/assertj/assertj-core-quick-start.html

No comments:

Post a Comment