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;
 
 @RunWith(MockitoJUnitRunner.class)
 public class MapOfMapTest {

     @InjectMocks
     private Processor processor;
     
     @Test
     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
         assertTrue(actual.equals(cusipMap));
         
         // 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));
     }
 } 

61 Comments:

  1. Connect effortlessly between Buffalo and Oakville with our premier Airport Limo and Taxi Transportation. Whether it’s a lavish limo or a convenient taxi, we provide reliable services tailored to your needs. Experience comfort and convenience on your journey from Buffalo to Oakville.

  2. Simplify your airport transportation with our O’Hare Airport Pickup/Drop Service. From shuttle buses to private transfers, we cater to diverse preferences. Experience seamless travel from O’Hare to downtown and beyond, ensuring a stress-free journey.

  3. The ability to present nuanced ideas so clearly is something I truly respect.

  4. The post added a new layer to my understanding of the subject. Thanks for sharing The knowledge.

  5. The unique perspective on this subject was enlightening. It’s refreshing to see someone so passionate about their topic.

  6. This post has been incredibly helpful, like a guiding hand in a crowded room. The guidance is much appreciated.

  7. This post was a breath of fresh air. Thank you for The unique insights!

  8. Consistently high-high quality content, as if you’re trying to show us all up.

  9. The post has broadened my perspective in ways I didn’t expect. Thank you for that.

  10. The approach to topics is like a master painter’s to a canvas, with each stroke adding depth and perspective.

  11. The insights are like a fine wine—rich, fulfilling, and leaving me wanting more.

Leave a Reply

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