AssertEquals 2列表忽略顺序

时间:2014-04-02 09:37:37

标签: java arrays unit-testing junit assertion

我认为这应该是一个非常简单的问题。但不知怎的,我在谷歌找不到答案。

假设我有2个字符串列表。首先包含“字符串A”和“字符串B”,第二个包含“字符串B”和“字符串A”(通知顺序不同)。我想用 JUnit 测试它们,以检查它们是否包含完全相同的字符串。

是否有任何断言检查忽略顺序的字符串的相等性?对于给定的示例org.junit.Assert.assertEquals抛出AssertionError

java.lang.AssertionError: expected:<[String A, String B]> but was:<[String B, String A]>

解决方法是首先对列表进行排序,然后将它们传递给断言。但我希望我的代码尽可能简单和干净。

我使用 Hamcrest 1.3 JUnit 4.11 Mockito 1.9.5

10 个答案:

答案 0 :(得分:58)

当你提到你使用Hamcrest时,我会选择其中一个收集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()));
    }

}

答案 1 :(得分:46)

您可以使用List.containsAll和JUnit的assertTrue来检查第一个列表是否包含第二个列表中的每个元素,反之亦然。

assertTrue(first.size() == second.size() && 
    first.containsAll(second) && second.containsAll(first));

答案 2 :(得分:8)

这是一个避免二次复杂度的解决方案(多次迭代列表)。这使用Apache Commons CollectionUtils类在列表中创建每个项目的Map到频率计数本身。然后它只是比较两个地图。

Assert.assertEquals("Verify same metrics series",
    CollectionUtils.getCardinalityMap(expectedSeriesList),
    CollectionUtils.getCardinalityMap(actualSeriesList));

我也刚刚发现了CollectionUtils.isEqualCollection声称完全按照这里要求做的事情......

https://commons.apache.org/proper/commons-collections/apidocs/index.html?org/apache/commons/collections4/CollectionUtils.html

答案 3 :(得分:2)

    Collections.sort(excepted);
    Collections.sort(actual);
    assertEquals(excepted,actual);

答案 4 :(得分:2)

使用AssertJ,您需要containsExactlyInAnyOrder()containsExactlyInAnyOrderElementsOf()

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");
    }    
}

答案 5 :(得分:1)

请注意,Roberto Izquierdo的解决方案一般具有二次复杂性。 HashSets上的解决方案总是具有线性复杂性:

assertTrue(first.size() == second.size() &&
        new HashSet(first).equals(new HashSet(second)));

答案 6 :(得分:1)

您可以使用junit-addons jar中的ListAssert

ListAssert.assertEquals(yourList, Arrays.asList(3, 4, 5));

答案 7 :(得分:0)

为了快速修复,我会检查两种方式:

assertTrue(first.containsAll(second));
assertTrue(second.containsAll(first));

尝试相同元素的数量不同的情况(例如1,1,2和1,2,2),我没有得到误报。

答案 8 :(得分:0)

我来晚了,但是这是我仅使用Junit的解决方案。任何想法都欢迎。

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);
}

答案 9 :(得分:0)

与其他答案类似,它们都引用了第三方工具,不正确或效率低下。

这是Java 8中的O(N)普通解决方案。

public static void assertContainsSame(Collection<?> expected, Collection<?> actual)
{
    assert expected.size() == actual.size();

    Map<Object, Long> counts = expected.stream()
        .collect(Collectors.groupingBy(
                item -> item,
                Collectors.counting()));

    for (Object item : actual)
        assert counts.merge(item, -1L, Long::sum) != -1L;
}
相关问题