Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Map equality using Hamcrest

I'd like to use hamcrest to assert that two maps are equal, i.e. they have the same set of keys pointing to the same values.

My current best guess is:

assertThat( affA.entrySet(), hasItems( affB.entrySet() ); 

which gives:

The method assertThat(T, Matcher<T>) in the type Assert is not applicable for the arguments (Set<Map.Entry<Householdtypes,Double>>, Matcher<Iterable<Set<Map.Entry<Householdtypes,Double>>>>)

I've also looked into variations of containsAll, and some others provided by the hamcrest packages. Can anyone point me in the right direction? Or do I have to write a custom matcher?

like image 700
mo-seph Avatar asked Mar 24 '10 16:03

mo-seph


People also ask

What is Hamcrest used for?

Hamcrest is a framework that assists writing software tests in the Java programming language. It supports creating customized assertion matchers ('Hamcrest' is an anagram of 'matchers'), allowing match rules to be defined declaratively. These matchers have uses in unit testing frameworks such as JUnit and jMock.

Why assertThat is deprecated?

assertThat method is deprecated. Its sole purpose is to forward the call to the MatcherAssert. assertThat defined in Hamcrest 1.3. Therefore, it is recommended to directly use the equivalent assertion defined in the third party Hamcrest library.

How do I use Hamcrest in eclipse?

Including HamcrestRight click on your eclipse project and select 'Properties' and then select 'Java Build Path' in the left pane and 'Libraries' on the right. On the 'Libraries' tab click the 'Add External Jars' button and navigate to the hamcrest-all jar you previously downloaded.


2 Answers

The shortest way I've come up with is two statements:

assertThat( affA.entrySet(), everyItem(isIn(affB.entrySet()))); assertThat( affB.entrySet(), everyItem(isIn(affA.entrySet()))); 

But you can probably also do:

assertThat(affA.entrySet(), equalTo(affB.entrySet())); 

depending on the implementations of the maps, and sacrificing the clarity of the difference report: that would just tell you that there is a difference, while the statement above would also tell you which one.

UPDATE: actually there is one statement that works independently of the collection types:

assertThat(affA.entrySet(), both(everyItem(isIn(affB.entrySet()))).and(containsInAnyOrder(affB.entrySet()))); 
like image 144
Hans-Peter Störr Avatar answered Oct 02 '22 13:10

Hans-Peter Störr


Sometimes Map.equals() is enough. But sometimes you don't know the types of Maps is returned by code under tests, so you don't know if .equals() will properly compare that map of unknown type returned by code with map constructed by you. Or you don't want to bind your code with such tests.

Additionally, constructing a map separately to compare the result with it is IMHO not very elegant:

Map<MyKey, MyValue> actual = methodUnderTest();  Map<MyKey, MyValue> expected = new HashMap<MyKey, MyValue>(); expected.put(new MyKey(1), new MyValue(10)); expected.put(new MyKey(2), new MyValue(20)); expected.put(new MyKey(3), new MyValue(30)); assertThat(actual, equalTo(expected)); 

I prefer using machers:

import static org.hamcrest.Matchers.hasEntry;  Map<MyKey, MyValue> actual = methodUnderTest(); assertThat(actual, allOf(                       hasSize(3), // make sure there are no extra key/value pairs in map                       hasEntry(new MyKey(1), new MyValue(10)),                       hasEntry(new MyKey(2), new MyValue(20)),                       hasEntry(new MyKey(3), new MyValue(30)) )); 

I have to define hasSize() myself:

public static <K, V> Matcher<Map<K, V>> hasSize(final int size) {     return new TypeSafeMatcher<Map<K, V>>() {         @Override         public boolean matchesSafely(Map<K, V> kvMap) {             return kvMap.size() == size;         }          @Override         public void describeTo(Description description) {             description.appendText(" has ").appendValue(size).appendText(" key/value pairs");         }     }; } 

And there is another variant of hasEntry() that takes matchers as parameters instead of exact values of key and value. This can be useful in case you need something other than equality testing of every key and value.

like image 41
Alexey Tigarev Avatar answered Oct 02 '22 12:10

Alexey Tigarev