Java – how to match the key value pairs of the map using mockito?
I need to send a specific value from a mock object based on a specific key value
Specific category:
map.put("xpath","PRICE"); search(map);
From test cases:
IoUrXMLDocument mock = mock(IoUrXMLDocument.class); when(mock.search(.....need help here).thenReturn("$100.00");
How do I simulate this method calling this key value pair?
Solution
I found that this tried to solve a similar problem by creating a mockito stub with a map parameter I don't want to write a custom matcher for relevant maps, and then I find a more elegant solution: use the additional matcher in hamcrest Library in argthat of mockito:
when(mock.search(argThat(hasEntry("xpath","PRICE"))).thenReturn("$100.00");
If you need to check multiple entries, you can use other good things of hamcrest:
when(mock.search(argThat(allOf(hasEntry("xpath","PRICE"),hasEntry("otherKey","otherValue")))).thenReturn("$100.00");
This started an extraordinary map for a long time, so I finally extracted methods to collect entry matchers and pasted them into our testutils:
public static <K,V> Matcher<Map<K,V>> matchesEntriesIn(Map<K,V> map) { return allOf(buildMatcherArray(map)); } public static <K,V>> matchesAnyEntryIn(Map<K,V> map) { return anyOf(buildMatcherArray(map)); } @SuppressWarnings("unchecked") private static <K,V> Matcher<Map<? extends K,? extends V>>[] buildMatcherArray(Map<K,V> map) { List<Matcher<Map<? extends K,? extends V>>> entries = new ArrayList<Matcher<Map<? extends K,? extends V>>>(); for (K key : map.keySet()) { entries.add(hasEntry(key,map.get(key))); } return entries.toArray(new Matcher[entries.size()]); }
So I stayed:
when(mock.search(argThat(matchesEntriesIn(map))).thenReturn("$100.00"); when(mock.search(argThat(matchesAnyEntryIn(map))).thenReturn("$100.00");
There is some ugliness associated with generics, and I'm suppressing a warning, but at least it's dry and hidden in testutil
As a final note, please note embedded hamcrest issues in JUnit 4.10 Using maven, I suggest importing hamcrest library first and then JUnit 4.11 (and excluding hamcrest core from JUnit is just for good measurement):
<dependency> <groupId>org.hamcrest</groupId> <artifactId>hamcrest-library</artifactId> <version>1.3</version> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> <exclusions> <exclusion> <groupId>org.hamcrest</groupId> <artifactId>hamcrest-core</artifactId> </exclusion> </exclusions> </dependency>