Junit:如何检查 2 collections 是否与不同顺序的元素相等?

Junit: How to check if 2 collections are equals with elements in different order?

我正在尝试使用断言检查两个 collections 是否相同。它们应该是相同的,即使它们的元素顺序不同。

这是我检查相等性的方法:

 public static <T> void assertCollectionsAreEquals (Collection<T> expected, Collection<T> actual, String message) {
        Assertions.assertEquals(expected, actual, message);    
        }

示例collections:

        Collection <Integer> one = new ArrayList<Integer>();
        Collection <Integer> two = new ArrayList<Integer>();
        Collection <Integer> three = new ArrayList<Integer>();

        one.add(1);
        one.add(2);
        two.add(1);
        two.add(2);
        three.add(2);
        three.add(1);

所以我的 collections 看起来像这样:

One:[1, 2]
Two:[1, 2]
Three:[2, 1]

测试:

assertCollectionsAreEquals(one, two, "Not Equals");
assertCollectionsAreEquals(one, three, "Not Equals");

输出:

Exception in thread "main" org.opentest4j.AssertionFailedError: Not Equals ==> expected: <[1, 2]> but was: <[2, 1]>

如何使我的所有测试都成功 collections?

要检查两个集合是否相等,应比较两个集合的大小,接下来可以通过从集合 c1 的副本中删除集合 c2 中的元素来计算差异,如果它是空的,集合是相等的:

public static <T> boolean areCollectionsEqual(Collection<T> c1, Collection<T> c2) {
    if (c1 == c2) return true;
    
    if (c1 == null || c2 == null || c1.size() != c2.size()) {
        return false;
    }
    
    Collection<T> tmp = new ArrayList<>(c1);
    for (T item : c2) {
        if (!tmp.remove(item)) {
            return false;
        }
    }
    
    return tmp.isEmpty();
}

这种方法允许比较不同类型的集合(例如 ListSet

那么常见的assertTrue / assertFalse可能会用在测试中:

public static <T> void assertCollectionsAreEqual(Collection<T> expected, Collection<T> actual, String message) {
    Assertions.assertTrue(areCollectionsEqual(expected, actual), message);    
}

public static <T> void assertCollectionsAreNotEqual(Collection<T> expected, Collection<T> actual, String message) {
    Assertions.assertFalse(areCollectionsEqual(expected, actual), message);    
}

Update Collection::removeAll 在集合包含具有不同频率的相同元素的情况下可能会产生不正确的结果。例如List.of (1, 2, 2, 2)List.of (1, 2, 1, 2),所以被迭代替换为remove

JUnit 5 中没有现成的断言方法来完成此任务。您可以改用 Hamcrest:

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsInAnyOrder;

assertThat("Not Equals", one, containsInAnyOrder(two.toArray()));
assertThat("Not Equals", one, containsInAnyOrder(three.toArray()));