How to use Hamcrest to inspect Map items
Solution 1
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")))));
}
Solution 2
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.
Solution 3
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.
dnang
Updated on June 01, 2021Comments
-
dnang almost 3 years
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 typeMatchers
is not applicable for the arguments(String, Matcher<Iterable<? super Object>>)
. For one thing I think Eclipse is confused of whichhasEntry
method I wanted to use, it should behasEntry(org.hamcrest.Matcher<? super K> keyMatcher, org.hamcrest.Matcher<? super V> valueMatcher)
, not thehasEntry(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?
-
John B over 10 yearsI don't believe this will resolve the compile-time error because the
hasEntry
will return aMatcher<String, Iterable<Object>>
instead of the requiredMatcher<String, List<MyItem>>
-
t0mppa over 10 years@JohnB: Believe it or not, but I tried it and it works just peachy for me.
-
rascio over 6 yearsShould it work also for map with values of different type (
Map<String, Object>
to say it in java)? Because I'm trying it with mockito, and I have anOverload resolution failed
compile error.