PUBLIC OBJECT

A helper method for unit testing Comparators

For the poker game I'm not writing, I wrote a Comparator to rank the player's hands.

Now to write a unit tests for that Comparator. Generally I find that it's hard to write test cases for Comparators. You end up having to puzzle over whether to use < 0 or > 0, and the orders of the arguments is significant:

public void testFlushIsAboveStraight() {
  PokerHand flush = PokerHand.fromString(" 2c  5c  6c 10c  Qc");
  PokerHand straight = PokerHand.fromString(" 7c  8d  9h 10s  Jh");
  assertTrue(new PokerHandComparator().compare(flush, straight) > 0);
}`</pre>Another problem with this test is that when it fails, the error message isn't particularly useful:<pre>`junit.framework.AssertionFailedError
  at PokerEngineTest.testFlushIsAboveStraight(PokerEngineTest.java:14)`</pre>

Recently I created a Comparator test that I think is quite natural and human readable:<pre>`void testSortingHands() {
  assertElementsOrderedLikeThis(
    PokerHand.fromString(" 3h  4h  4s  Kc  As"), // low pair
    PokerHand.fromString(" 3h  4h  6s  Ac  As"), // high pair
    PokerHand.fromString(" 3d  4d  4h  9c  9s"), // two pairs
    PokerHand.fromString(" 4h  6d 10s 10c 10d"), // three of a kind
    PokerHand.fromString(" 7c  8d  9h 10s  Jh"), // straight
    PokerHand.fromString(" 2c  5c  6c 10c  Qc")  // flush
  );
}`</pre>

This code uses a helper `assert` method I wrote for testing comparators. This method can be used to test any Comparator (or [Comparable](http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Comparable.html)) in a human-readable way:<pre>`private &lt;T&gt; void assertElementsOrderedLikeThis(
      Comparator &lt;? super T&gt; comparator, T... elements) {
  List&lt;T&gt; expectedOrder = Arrays.asList(elements);

  List&lt;T&gt; shuffledAndSorted = new ArrayList&lt;T&gt;(expectedOrder);
  Collections.shuffle(shuffledAndSorted, new Random(0));
  Collections.sort(shuffledAndSorted, comparator);
  assertEquals(expectedOrder, shuffledAndSorted);

  List&lt;T&gt; reversedAndSorted = new ArrayList&lt;T&gt;(expectedOrder);
  Collections.reverse(reversedAndSorted);
  Collections.sort(reversedAndSorted, comparator);
  assertEquals(expectedOrder, reversedAndSorted);
}

Another nice thing about this approach is that in the event of a test failure, the error message includes the expected and actual values.