0

I'm quite new to using hamcrest for asserts, and I've already got a pretty nasty case to test.

We've got 2 arraylists of different, custom objects: FilterItem and MyEnum. Both contain a property - let's say 'value' - which should be equal for the unittests to pass. Because the objects are different I cannot simply assertThat (filterItems, hasItems(expectedEnums)), so I'd like to assert the values they contain, which makes it alot more difficult.

In each unittest where I'd like to assert this, I've extracted the assert-logic to a new method, as shown below:

private void assertIfFilterItemValuesAreEqualToExpectedEnumValues(ArrayList<FilterItem> filterItems, ArrayList<MyEnum> expectedEnums)
{
   ArrayList<String> filterItemValues = getFilterItemValues(filterItems);

   assertEquals(expectedEnums.size(), filterItemValues.size());
   // This assert prevents unittests to pass unfairly, in case the array is empty
   assertFalse("No expectedEnums to assert!", expectedEnums.isEmpty());

   for (MyEnum myEnum : expectedEnums)
   {
      String myEnumValue = myEnum.getValue();
      assertThat(filterItemValues, hasItem(myEnumValue));
   }
 }

private ArrayList<String> getFilterItemValues(ArrayList<FilterItem> filterItems)
{
   ArrayList<String> filterItemValues = new ArrayList<>();
   for (FilterWaardeItem filterItem : filterItems)
   {
      filterItemValues.add(filterItem.value);
   }
   return filterItemValues;
}

The unittests all pass now, so I guess the implementation is correct, but I've got the feeling the implementation could be more simple. My feeling is that at least the for-loop for the enum could be left out. Additionally, if the solution could make the 2 asserts previous to the for-loop unnecessary as well, that would be great! Probably hasProperty() and contains()might be part of the solution?

Any advice?

ps. the current test does not assert whether the order of the lists are the same, but that's the next unittest I'd like to create. If anyone could give a nice solution for that one as well (without using all the for-loops), I'd really appreciate it!

Patrick Kuijpers
  • 362
  • 1
  • 3
  • 8

2 Answers2

0

You can map the actual and expected list beforehand and then use contains:

private void assertIfFilterItemValuesAreEqualToExpectedEnumValues(ArrayList<FilterItem> filterItems, ArrayList<MyEnum> expectedEnums) {
    List<String> actual = filterItems.stream()
            .map(item -> item.value)
            .collect(toList());
    String[] expected = expectedEnums.stream()
            .map(myEnum -> myEnum.getValue())
            .toArray(String[]::new);

    assertThat(actual, contains(expected));
}

This also asserts that the order is the same. I used the new stream api for the mapping.

eee
  • 3,241
  • 1
  • 17
  • 34
0

You can use the hamcrest contains method that accepts a list of matchers. You create a list of matchers from the expectedEnums being each item in the list a hasProperty matcher with the enum in the list.

    final List<Matcher<? super Object>> enumListMatcher = expectedEnums.stream()
            .map(myEnum -> hasProperty("value", is(myEnum.getValue()))).collect(Collectors.toList());
    assertThat(filterItems, contains(enumListMatcher));

NOTE: it works as long as you have a getter for value in FilterItem.

Ruben
  • 3,986
  • 1
  • 21
  • 34