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>
