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));
}
}
Thanks for the info, I found the answer to my question in it.