How to approve a card contains a card with a record

I have a unit test that should check the value of a nested map. I can make my statement work by pulling out the record and matching the base Map , but I was looking for a clear way to show what the statement does. Here is a very simplified test:

 import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasEntry; import java.util.HashMap; import java.util.Map; import org.junit.Test; public class MapContainsMapTest { @Test public void testMapHasMap() { Map<String, Object> outerMap = new HashMap<String, Object>(); Map<String, Object> nestedMap = new HashMap<String, Object>(); nestedMap.put("foo", "bar"); outerMap.put("nested", nestedMap); // works but murky assertThat((Map<String, Object>) outerMap.get("nested"), hasEntry("foo", "bar")); // fails but clear assertThat(outerMap, hasEntry("nested", hasEntry("foo", "bar"))); } } 

It seems the problem is comparing the external card using hasEntry(K key, V value) , while I want to use hasEntry(Matcher<? super K> keyMatcher, Matcher<? super V> valueMatcher) . I am not sure how to force the statement to use the second form.

Thanks in advance.

+8
java junit hamcrest
source share
3 answers

I would probably expand the new Matcher for this, something like this (be careful, NPEs are hiding):

 class SubMapMatcher extends BaseMatcher<Map<?,?>> { private Object key; private Object subMapKey; private Object subMapValue; public SubMapMatcher(Object key, Object subMapKey, Object subMapValue) { super(); this.key = key; this.subMapKey = subMapKey; this.subMapValue = subMapValue; } @Override public boolean matches(Object item) { Map<?,?> map = (Map<?,?>)item; if (!map.containsKey(key)) { return false; } Object o = map.get(key); if (!(o instanceof Map<?,?>)) { return false; } Map<?,?> subMap = (Map<?,?>)o; return subMap.containsKey(subMapKey) && subMap.get(subMapKey).equals(subMapValue); } @Override public void describeTo(Description description) { description.appendText(String.format("contains %s -> %s : %s", key, subMapKey, subMapValue)); } public static SubMapMatcher containsSubMapWithKeyValue(String key, String subMapKey, String subMapValue) { return new SubMapMatcher(key, subMapKey, subMapValue); } } 
+2
source share

If you declare outerMap as Map<String, Map<String, Object>> , you don't need an ugly cast. Like this:

 public class MapContainsMapTest { @Test public void testMapHasMap() { Map<String, Map<String, Object>> outerMap = new HashMap<>(); Map<String, Object> nestedMap = new HashMap<>(); nestedMap.put("foo", "bar"); outerMap.put("nested", nestedMap); assertThat(outerMap.get("nested"), hasEntry("foo", "bar")); } } 
+2
source share

If you want to put Map<String, Object> as values โ€‹โ€‹in outerMap , adjust the declaration accordingly. Then you can do

 @Test public void testMapHasMap() { Map<String, Map<String, Object>> outerMap = new HashMap<>(); Map<String, Object> nestedMap = new HashMap<String, Object>(); nestedMap.put("foo", "bar"); outerMap.put("nested", nestedMap); Object value = "bar"; assertThat(outerMap, hasEntry(equalTo("nested"), hasEntry("foo", value))); } 

Object value = "bar"; required for compilation. Alternatively you can use

 assertThat(outerMap, hasEntry(equalTo("nested"), Matchers.<String, Object> hasEntry("foo", "bar"))); 
+2
source share

All Articles