AssertEquals 2 목록은 순서를 무시합니다.


82

정말 간단한 질문이어야한다고 생각합니다. 하지만 어떻게 든 Google에서 답을 찾을 수 없습니다.

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를 사용 합니다.


3
list1.removeAll(list2)비워 list1두어야합니다. 나는 당신이 원하는 것을 얻기 위해 이것을 만들 수 있다고 생각합니다.
SudoRahul 2014

6
containsAll하고 removeAll있는 O(n²)평등은 그들과 테스트를 정렬하는 동안 목록에 대한 O(nlogn). Collections.sort(list1); Collections.sort(list2); assertTrue(list1.equals(list2));또한 깨끗합니다.
Alexis C.

1
의 중복 가능성 Hamcrest는 컬렉션 비교

@SudoRahul-목록을 모두 제거하여 수정하지 않으려면 어떻게합니까?
Erran Morad

@BoratSagdiyev-OP의 제약이 아니기 때문에 제안했습니다. 그러나 그것이 제약이라면이 질문에 대한 대답은 당면한 문제를 해결합니다.
SudoRahul

답변:


92

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

}

5
내 대답을 참조 stackoverflow.com/a/38262680/297710 하는 프로그램, containsInAnyOrder와 모든 어설에서 Hamcrest 매처 (matcher)와 피할 ".toArray ()"를 개선하는 방법
yvolk

57

JUnit의 assertTrue 와 함께 List.containsAll 을 사용 하여 첫 번째 목록에 두 번째 목록의 모든 요소가 포함되어 있는지 확인하고 그 반대의 경우도 마찬가지입니다.

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

2
@kukis 상황에 따라 중복을 확인 하시겠습니까?
robertoia 2014-04-02

4
네, 물론입니다. 2 개의 주어진 목록은 순서를 무시하고 정확히 동일해야합니다.
kukis 2014-04-02

2
@kukis 질문에 대한 ZouZou의 의견을 확인하십시오.
robertoia 2014

1
.. 포함 assertEquals(first.size(), second.size())할 수 있습니다 .. 그런 다음 예상대로 작동합니다
확실히 정의 할 수 없습니다

17
목록의 중복 항목에서는 작동하지 않습니다. 여기에 설명 할 예가 있습니다 List<String> list1 = Arrays.asList("a", "a", "b"); List<String> list2 = Arrays.asList("a", "b", "b"); assertEquals(list1.size(), list2.size()); assertTrue(list1.containsAll(list2) && list2.containsAll(list1)); .이 예에서 두 어설 션 모두 목록이 실제로 다른지 감지하지 못합니다. @AlexWorden은 Apache Commons Collections의 CollectionUtils.isEqualCollection ()을 언급하며,이 예에서는 컬렉션이 동일하지 않음을 올바르게 감지합니다.
desilvai

11

다음은 2 차 복잡성을 피하는 솔루션입니다 (목록을 여러 번 반복). 이것은 Apache Commons CollectionUtils 클래스를 사용하여 목록에서 빈도 수 자체에 대한 각 항목의 맵을 생성합니다. 그런 다음 단순히 두 개의지도를 비교합니다.

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


4

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

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

2

파티에 늦었지만 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);
}

1

Roberto Izquierdo의 솔루션에는 일반적으로 2 차 복잡성이 있습니다. HashSet의 솔루션에는 항상 선형 복잡성이 있습니다.

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

2
그 접근 방식은 작동하지 않습니다. 첫 번째가 ( "문자열 A")이고 두 번째가 ( "문자열 A", "문자열 A")이면 동일한 목록이 아닙니다.
Alexis C.

4
크기를 확인할 수 없습니다. 첫 번째 ("s1", "s2", "s3" ,"s1")와 두 번째는 ("s2", "s1", "s3" ,"s2");동일한 목록이 아닙니다.
Alexis C.

@ZouZou 허용 된 솔루션에는 동일한 문제가 있습니다. 당신은 정말 정확한 해결책을 제안했습니다. 당신이 대답하면 나는 그것을 찬성 할 것입니다.
leventov 2014

@ZouZou 동일한 목록은 아니지만 정확히 동일한 문자열을 포함합니다. OP, 명확히?. 또한 답변을 작성하고 나도 찬성 할 것입니다. :) 생각하지 않았습니다.
robertoia 2014

2
이것은 여전히 ​​모든 경우 ( "A", "A", "B")에 대해 정확하지 않습니다. ( "A", "B", "B")와 같은 것으로 비교됩니다.
Tim B

1

빠른 수정을 위해 두 가지 방법을 모두 확인합니다.

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

그리고 동일한 요소의 수가 다른 상황 (예 : 1, 1, 2 및 1, 2, 2)에서 시도해 보았습니다. 오 탐지가 발생하지 않았습니다.


1
코드는 여전히 실패합니다. 이 예제를 참조하십시오-@Test public void test1 () {List <String> list1 = Arrays.asList ( "a", "a", "b"); List <String> list2 = Arrays.asList ( "a", "b", "b"); Assert.assertTrue (list1.containsAll (list2)); Assert.assertTrue (list2.containsAll (list1)); }
Erran Morad

1

junit-addons jar에 포함 된 ListAssert 를 사용할 수 있습니다 .

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

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;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.