JUnit Testing a Map of Maps – Map<String, Map<String, Object>>

Let’s say you encounter a situation where you have a Map of Maps where the nested Map has a value of Object. These were the cards I was dealt while refactoring a bit of code recently. This case may be a bit too generic and likely warrants a more specific domain object at the least; however, I maintained this structure to remain backward compatible I did some TDD to make sure nothing was broken by the refactoring.

There are many options for unit testing a Map of Maps, but I’m particularly more fond of the assertThat approach with Matchers. I will always strive to use these over the rudimentary assertEquals, assertTrue and assertFalse, which provides little value for reporting and troubleshooting. Hamcrest is one of those open-source libraries in Java that has become so popular that it has basically received the ultimate form of flattery in the newer versions of Java’s JUnit. Below you can find several examples of how to leverage JUnit to test Maps of Maps:

 import org.hamcrest.CoreMatchers;
 import org.hamcrest.collection.IsMapContaining;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.junit.MockitoJUnitRunner;

 import java.io.IOException;
 import java.util.HashMap;
 import java.util.Map;
 import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.notNullValue;
 import static org.hamcrest.collection.IsMapContaining.hasEntry;
 public class MapOfMapTest {

     private Processor processor;
     public void testProcess_CloseIsTrue_ExpectTrue() throws Exception {
         // setup
         // when
         // test
         Map<String, Map<String, Object>> mapOfMaps = (Map<String, Map<String, Object>>) processor.process();
         assertThat(mapOfMaps, is(notNullValue()));

         Map<String, Object> cusipMap = new HashMap<>();
         cusipMap.put("ticker", "BGNIXS");
         String cusip = "091929695";
         cusipMap.put("cusip", cusip);
         cusipMap.put("name", "BlackRock GNMA Instl");
         cusipMap.put("closed", true);
         cusipMap.put("scale", 3);
         Map<String, Object> actual = mapOfMaps.get(cusip);
         compareMaps(mapOfMaps, cusipMap, cusip, actual);

     protected void compareMaps(Map<String, Map<String, Object>> mapOfMaps, Map<String, Object> cusipMap, String cusip,
         Map<String, Object> actual) {
         // The most basic pure JUnit assertion, but probably the least preferred option. This is not expressive and will provide poor feedback on failure
         // The second most basic pure JUnit assertion, and only marginally better than the above. This is not expressive and will provide poor feedback on failure
         assertEquals(actual, cusipMap);
         // Mildly more expressive and would be preferred in my opinion over the above two options
         assertThat(actual, is(cusipMap));
         // ----------------------------------------------------------------------------------------------------

         // Using Hamcrest CoreMatchers - more expressive than the above
         assertThat(actual, CoreMatchers.<Map<String, Object>>equalTo(cusipMap));
         // Using Hamcrest CoreMatchers - check a specific key and value and is more expressive than the above
         assertThat(mapOfMaps, hasEntry(equalTo(cusip), CoreMatchers.<Map<String, Object>>equalTo(cusipMap)));
         // ----------------------------------------------------------------------------------------------------
         // Using Hamcrest: Ensure the key used for the outer map is present
         assertThat(mapOfMaps, IsMapContaining.hasKey(cusip));
         // Using Hamcrest: Ensure the actual inner Map value is present in the output Map ... this is obvious
         assertThat(mapOfMaps, IsMapContaining.hasValue(actual));
         // Using Hamcrest: Ensure the generated inner Map value is present in the output Map ... this is the more valid test
         assertThat(mapOfMaps, IsMapContaining.hasValue(cusipMap));
         // Using Hamcrest: Two for one assertion that takes care of checking the key and the value ... use this one
         assertThat(mapOfMaps, IsMapContaining.hasEntry(cusip, cusipMap));

Leave a Reply

Your email address will not be published. Required fields are marked *