JUnit 4 compare Sets
How w开发者_JAVA百科ould you succinctly assert the equality of Collection
elements, specifically a Set
in JUnit 4?
You can assert that the two Set
s are equal to one another, which invokes the Set
equals()
method.
public class SimpleTest {
private Set<String> setA;
private Set<String> setB;
@Before
public void setUp() {
setA = new HashSet<String>();
setA.add("Testing...");
setB = new HashSet<String>();
setB.add("Testing...");
}
@Test
public void testEqualSets() {
assertEquals( setA, setB );
}
}
This @Test
will pass if the two Set
s are the same size and contain the same elements.
Apache commons to the rescue again.
assertTrue(CollectionUtils.isEqualCollection(coll1, coll2));
Works like a charm. I don't know why but I found that with collections the following assertEquals(coll1, coll2)
doesn't always work. In the case where it failed for me I had two collections backed by Sets. Neither hamcrest nor junit would say the collections were equal even though I knew for sure that they were. Using CollectionUtils it works perfectly.
with hamcrest:
assertThat(s1, is(s2));
with plain assert:
assertEquals(s1, s2);
NB:t the equals() method of the concrete set class is used
A particularly interesting case is when you compare
java.util.Arrays$ArrayList<[[name,value,type], [name1,value1,type1]]>
and
java.util.Collections$UnmodifiableCollection<[[name,value,type], [name1,value1,type1]]>
So far, the only solution I see is to change both of them into sets
assertEquals(new HashSet<CustomAttribute>(customAttributes), new HashSet<CustomAttribute>(result.getCustomAttributes()));
Or I could compare them element by element.
As an additional method that is array based ... you can consider using unordered array assertions in junitx . Although the Apache CollectionUtils example will work, there is a pacakge of solid assertion extensions there as well :
I think that the
ArrayAssert.assertEquivalenceArrays(new Integer[]{1,2,3}, new Integer[]{1,3,2});
approach will be much more readable and debuggable for you (all Collections support toArray(), so it should be easy enough to use the ArrayAssert methods.
Of course the downside here is that, junitx is an additional jar file or maven entry...
<dependency org="junit-addons" name="junit-addons" rev="1.4"/>
Check this article. One example from there:
@Test
public void listEquality() {
List<Integer> expected = new ArrayList<Integer>();
expected.add(5);
List<Integer> actual = new ArrayList<Integer>();
actual.add(5);
assertEquals(expected, actual);
}
Using Hamcrest:
assertThat( set1, both(everyItem(isIn(set2))).and(containsInAnyOrder(set1)));
This works also when the sets have different datatypes, and reports on the difference instead of just failing.
I like the solution of Hans-Peter Störr... But I think it is not quite correct. Sadly containsInAnyOrder
does not accept a Collection
of objetcs to compare to. So it has to be a Collection
of Matcher
s:
assertThat(set1, containsInAnyOrder(set2.stream().map(IsEqual::equalTo).collect(toList())))
The import are:
import static java.util.stream.Collectors.toList;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.junit.Assert.assertThat;
If you want to check whether a List or Set contains a set of specific values (instead of comparing it with an already existing collection), often the toString method of collections is handy:
String[] actualResult = calltestedmethod();
assertEquals("[foo, bar]", Arrays.asList(actualResult).toString());
List otherResult = callothertestedmethod();
assertEquals("[42, mice]", otherResult.toString());
This is a bit shorter than first constructing the expected collection and comparing it with the actual collection, and easier to write and correct.
(Admittedly, this is not a particularily clean method, and can't distinguish an element "foo, bar" from two elements "foo" and "bar". But in practice I think it's most important that it's easy and fast to write tests, otherwise many developers just won't without being pressed.)
精彩评论