assertThat - hamcrest - check if list is sorted

lukaszrys picture lukaszrys · Nov 6, 2013 · Viewed 20.2k times · Source

Ok I think its going to be a short question. I have an ArrayList that I sorted by date, of course I see it works but I would also like to write a test for it.

I want to check if next value (date) in my list is lower then previous one. I am able to do that with using some for s and adding temp list, but I'm wondering if there's a easier solution. I read in hamrest documentation that there's somethink like contains(hamrest contains) that iterate through an object (list,map etc) but still I have no idea what to do next.

Answer

ThanksForAllTheFish picture ThanksForAllTheFish · Nov 6, 2013

[First Option]: you can write your own Matcher. Something like (disclaimer: this is just a sample code, it is not tested and may be not perfect):

@Test
  public void theArrayIsInDescendingOrder() throws Exception
  {
    List<Integer> orderedList = new ArrayList<Integer>();
    orderedList.add(10);
    orderedList.add(5);
    orderedList.add(1);
    assertThat(orderedList, isInDescendingOrdering());
  }

  private Matcher<? super List<Integer>> isInDescendingOrdering()
  {
    return new TypeSafeMatcher<List<Integer>>()
    {
      @Override
      public void describeTo (Description description)
      {
        description.appendText("describe the error has you like more");
      }

      @Override
      protected boolean matchesSafely (List<Integer> item)
      {
        for(int i = 0 ; i < item.size() -1; i++) {
          if(item.get(i) <= item.get(i+1)) return false;
        }
        return true;
      }
    };
  }

This example is with Integers but you can do it with Dates easily.

[Second option], based on the reference to contains in the OP's question: you can create a second list, ordering the original one, than using assertThat(origin, contains(ordered)). This way the eventual error is more precisely described since, if an element is not in the expected order, it will be pointed out. For example, this code

@Test
  public void testName() throws Exception
  {
    List<Integer> actual = new ArrayList<Integer>();
    actual.add(1);
    actual.add(5);
    actual.add(3);
    List<Integer> expected = new ArrayList<Integer>(actual);
    Collections.sort(expected);
    assertThat(actual, contains(expected.toArray()));
  }

will generate the description

java.lang.AssertionError: 
Expected: iterable containing [<1>, <3>, <5>]
     but: item 1: was <5>
    at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
    at org.junit.Assert.assertThat(Assert.java:865)
    at org.junit.Assert.assertThat(Assert.java:832)
    ...