Question

I have been recently using Hamcrest library to write some tests and quite successful but now I need to do something more complex and started to see a lot of difficulties. I need to inpsect and verify the properties of the items in a Map. My production code looks something like this:

    Map<String, List<MyItem>> map = new HashMap<String, List<MyItem>>();
    map.put("one", Arrays.asList(new MyItem("One")));
    map.put("two",  Arrays.asList(new MyItem("Two")));
    map.put("three",  Arrays.asList(new MyItem("Three")));

I want to write some test codes like the following, but it doesn't compile. Looks like Hamcrest's hasEntry is type-parametered, while hasItem and hasProperty only expect Object.

    assertThat(map, Matchers.<String, List<MyItem>>hasEntry("one",  hasItem(hasProperty("name", is("One")))));

My IDE (Eclipse) is giving this error message: The parameterized method <String, List<HamcrestTest.MyItem>>hasEntry(String, List<HamcrestTest.MyItem>) of type Matchers is not applicable for the arguments (String, Matcher<Iterable<? super Object>>). For one thing I think Eclipse is confused of which hasEntry method I wanted to use, it should be hasEntry(org.hamcrest.Matcher<? super K> keyMatcher, org.hamcrest.Matcher<? super V> valueMatcher) , not the hasEntry(K key, V value).

Should I just give up and get the item from the Map and manually inspect each property? Is there a cleaner way?

Was it helpful?

Solution

Youu could just use contains or containsInAnyOrder. True, you'll have to list all items in the List that way, but it works cleaner than hasItem:

@SuppressWarnings("unchecked")
@Test
public void mapTest() {
  Map<String, List<MyItem>> map = new HashMap<String, List<MyItem>>();
  map.put("one", asList(new MyItem("1"), new MyItem("one")));

  assertThat(map, hasEntry(is("one"),
                           containsInAnyOrder(hasProperty("name", is("one")),
                                              hasProperty("name", is("1")))));
}

OTHER TIPS

Since @t0mppa didn't provide a good example on how to use Hamcrest's contains and containsInAnyOrder for this, here's a little something to get your started:

Map<Integer, String> columns = new HashMap<Integer, String>();
columns.put(1, "ID");
columns.put(2, "Title");
columns.put(3, "Description");

assertThat(columns.values(), contains("ID", "Title", "Description")); // passes
assertThat(columns.values(), contains("ID", "Description", "Title")); // fails
assertThat(columns.values(), containsInAnyOrder("ID", "Description", "Title")); // passes

Note that as opposed to hasItem and hasItems, these will only work if you provide them with a full list of all the values you'll be matching against. See Hamcrest's javadocs for more information.

So just to make this simpler you might try this...

assertThat((Object)map, (Matcher)Matchers.hasEntry("one",  hasItem(hasProperty("name", is("One")))));

by going to a raw type you will get a warning but no compile error. If have used this trick in the past when I don't want to worry about getting all the casting just right for the compiler.

Also, you might consider using ItIterableContainingInOrder.containingInOrder(new MyItem("One"))). This will verify the entire list and if MyItem implements equals then you won't be using reflection in your tests.

the hasEntry method has two signatures:

  • hasEntry(key, value)
  • hasEntry(matcher<key>, matcher<value>)

You are using the first signature, thus you are checking whether your map contains a matcher mapped to the string "one". t0mppa's answer is using the second signature, that's why it works. The good news is you don't need to list all the elements in the list, you can just

assertThat(map, hasEntry(is("one"), hasItem(hasProperty("name", is("One")))));
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top