Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Mockito, how do I match against the key-value pair of a map?

Tags:

I need to send a specific value from a mock object based on a specific key value.

From the concrete class:

map.put("xpath", "PRICE"); search(map); 

From the test case:

IOurXMLDocument mock = mock(IOurXMLDocument.class); when(mock.search(.....need help here).thenReturn("$100.00"); 

How do I mock this method call for this key value pair?

like image 327
Sean Avatar asked Apr 05 '10 18:04

Sean


People also ask

How do I see exceptions in Mockito?

For checking the cause of the exception, I use: expectedException. expectCause(Mockito. sameInstance(expectedException)) or expectedException.

What does initMocks do in Mockito?

initMocks(this); initializes fields annotated with Mockito annotations. Allows shorthand creation of objects required for testing. Minimizes repetitive mock creation code. Makes the test class more readable.

Can we mock interface using Mockito?

The Mockito. mock() method allows us to create a mock object of a class or an interface. We can then use the mock to stub return values for its methods and verify if they were called.

Which Mockito methods are used to handle the exception in case of test methods?

Master Java Unit testing with Spring Boot and MockitoMockito provides the capability to a mock to throw exceptions, so exception handling can be tested. Take a look at the following code snippet. //add the behavior to throw exception doThrow(new Runtime Exception("divide operation not implemented")) .


1 Answers

I found this trying to solve a similar issue creating a Mockito stub with a Map parameter. I didn't want to write a custom matcher for the Map in question and then I found a more elegant solution: use the additional matchers in hamcrest-library with mockito's argThat:

when(mock.search(argThat(hasEntry("xpath", "PRICE"))).thenReturn("$100.00"); 

If you need to check against multiple entries then you can use other hamcrest goodies:

when(mock.search(argThat(allOf(hasEntry("xpath", "PRICE"), hasEntry("otherKey", "otherValue")))).thenReturn("$100.00"); 

This starts to get long with non-trivial maps, so I ended up extracting methods to collect the entry matchers and stuck them in our TestUtils:

import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.anyOf; import static org.hamcrest.Matchers.hasEntry;  import java.util.ArrayList; import java.util.List; import java.util.Map;  import org.hamcrest.Matcher; --------------------------------- public static <K, V> Matcher<Map<K, V>> matchesEntriesIn(Map<K, V> map) {     return allOf(buildMatcherArray(map)); }  public static <K, V> Matcher<Map<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'm left with:

when(mock.search(argThat(matchesEntriesIn(map))).thenReturn("$100.00"); when(mock.search(argThat(matchesAnyEntryIn(map))).thenReturn("$100.00"); 

There's some ugliness associated with the generics and I'm suppressing one warning, but at least it's DRY and hidden away in the TestUtil.

One last note, beware the embedded hamcrest issues in JUnit 4.10. With Maven, I recommend importing hamcrest-library first and then JUnit 4.11 (now 4.12) and exclude hamcrest-core from JUnit just for good measure:

<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.12</version>     <scope>test</scope>     <exclusions>         <exclusion>             <groupId>org.hamcrest</groupId>             <artifactId>hamcrest-core</artifactId>         </exclusion>     </exclusions> </dependency> <dependency>     <groupId>org.mockito</groupId>     <artifactId>mockito-all</artifactId>     <version>1.9.5</version>     <scope>test</scope> </dependency> 

Edit: Sept 1, 2017 - Per some of the comments, I updated my answer to show my Mockito dependency, my imports in the test util, and a junit that is running green as of today:

import static blah.tool.testutil.TestUtil.matchesAnyEntryIn; import static blah.tool.testutil.TestUtil.matchesEntriesIn; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; import static org.mockito.Matchers.argThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when;  import java.util.HashMap; import java.util.Map;  import org.junit.Test;  public class TestUtilTest {      @Test     public void test() {         Map<Integer, String> expected = new HashMap<Integer, String>();         expected.put(1, "One");         expected.put(3, "Three");          Map<Integer, String> actual = new HashMap<Integer, String>();         actual.put(1, "One");         actual.put(2, "Two");          assertThat(actual, matchesAnyEntryIn(expected));          expected.remove(3);         expected.put(2, "Two");         assertThat(actual, matchesEntriesIn(expected));     }      @Test     public void mockitoTest() {         SystemUnderTest sut = mock(SystemUnderTest.class);         Map<Integer, String> expected = new HashMap<Integer, String>();         expected.put(1, "One");         expected.put(3, "Three");          Map<Integer, String> actual = new HashMap<Integer, String>();         actual.put(1, "One");          when(sut.search(argThat(matchesAnyEntryIn(expected)))).thenReturn("Response");         assertThat(sut.search(actual), is("Response"));     }      protected class SystemUnderTest {         // We don't really care what this does         public String search(Map<Integer, String> map) {             if (map == null) return null;             return map.get(0);         }     } } 
like image 86
Marquee Avatar answered Sep 28 '22 05:09

Marquee