问题
That should be really simple question I believe. But somehow I can\'t find answer in Google.
Assume that I have 2 Lists of Strings. First contains \"String A\" and \"String B\", second one contains \"String B\" and \"String A\" (notice difference in order). I want to test them with JUnit to check whether they contains exactly the same Strings.
Is there any assert that checks equality of Strings that ignore order? For given example org.junit.Assert.assertEquals throws AssertionError
java.lang.AssertionError: expected:<[String A, String B]> but was:<[String B, String A]>
Work around is to sort Lists firstly and then pass them to assertion. But I want my code to be as simple and clean as possible.
I use Hamcrest 1.3, JUnit 4.11, Mockito 1.9.5.
回答1:
As you mention that you use Hamcrest, I would pick one of the collection Matchers
import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder;
import static org.junit.Assert.assertThat;
public class CompareListTest {
@Test
public void compareList() {
List<String> expected = Arrays.asList("String A", "String B");
List<String> actual = Arrays.asList("String B", "String A");
assertThat("List equality without order",
actual, containsInAnyOrder(expected.toArray()));
}
}
回答2:
You can use List.containsAll with JUnit's assertTrue to check that the first list contains every element from the second one, and vice versa.
assertTrue(first.size() == second.size() &&
first.containsAll(second) && second.containsAll(first));
回答3:
Here's a solution that avoids quadratic complexity (iterating over the lists multiple times). This uses the Apache Commons CollectionUtils class to create a Map of each item to a frequency count itself in the list. It then simply compares the two Maps.
Assert.assertEquals("Verify same metrics series",
CollectionUtils.getCardinalityMap(expectedSeriesList),
CollectionUtils.getCardinalityMap(actualSeriesList));
I also just spotted CollectionUtils.isEqualCollection that claims to do exactly what is being requested here...
https://commons.apache.org/proper/commons-collections/apidocs/index.html?org/apache/commons/collections4/CollectionUtils.html
回答4:
Collections.sort(excepted);
Collections.sort(actual);
assertEquals(excepted,actual);
回答5:
With AssertJ, containsExactlyInAnyOrder()
or containsExactlyInAnyOrderElementsOf()
is what you need :
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.List;
public class CompareListTest {
@Test
public void compareListWithTwoVariables() {
List<String> expected = Arrays.asList("String A", "String B");
List<String> actual = Arrays.asList("String B", "String A");
Assertions.assertThat(actual)
.containsExactlyInAnyOrderElementsOf(expected);
}
@Test
public void compareListWithInlineExpectedValues() {
List<String> actual = Arrays.asList("String B", "String A");
Assertions.assertThat(actual)
.containsExactlyInAnyOrder("String A", "String B");
}
}
回答6:
Note that solution by Roberto Izquierdo has quadratic complexity in general. Solution on HashSets always has linear complexity:
assertTrue(first.size() == second.size() &&
new HashSet(first).equals(new HashSet(second)));
回答7:
Im late to the party but here's my solution using Junit only. Any thoughts are welcome.
List<String> actual = new ArrayList<>();
actual.add("A");
actual.add("A");
actual.add("B");
List<String> expected = new ArrayList<>();
actual.add("A");
actual.add("B");
actual.add("B");
//Step 1: assert for size
assertEquals(actual.size(), expected.size());
//Step 2: Iterate
for(String e: expected){
assertTrue(actual.contains(e));
actual.remove(e);
}
回答8:
You can use ListAssert that comes in junit-addons jar.
ListAssert.assertEquals(yourList, Arrays.asList(3, 4, 5));
回答9:
For a quick fix I would check both ways:
assertTrue(first.containsAll(second));
assertTrue(second.containsAll(first));
And trying with a situation where the number of the same elements is different (e.g. 1, 1, 2 and 1, 2, 2) I didn't get false positives.
来源:https://stackoverflow.com/questions/22807328/assertequals-2-lists-ignore-order