我认为这应该是一个非常简单的问题。但不知怎的,我在谷歌找不到答案。
假设我有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 。
答案 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声称完全按照这里要求做的事情......
答案 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;
}