Junit에서 2 개의 목록 사이에 Assert가 동일


165

JUnit 테스트 케이스 에서 목록 사이에 동등 어설 션을 어떻게 만들 수 있습니까? 평등은 목록의 내용 사이에 있어야합니다.

예를 들면 다음과 같습니다.

List<String> numbers = Arrays.asList("one", "two", "three");
List<String> numbers2 = Arrays.asList("one", "two", "three");
List<String> numbers3 = Arrays.asList("one", "two", "four"); 

// numbers should be equal to numbers2
//numbers should not be equal to numbers3

5
나는 assertArrayEquals요즘 사용하고 싶다 . 와 함께 사용하십시오 List#toArray.
Thibstars

@ Thibstars-답변으로 찬성했습니다.
dfrankow

2
assertArrayEquals목록에서 배열을 가져와야합니다. assertIterableEquals
ThetaSinner

assertIterableEqualsjUnit5 @ThetaSinner
iec2011007

답변:


170

나는 이것이 몇 년 전에 요청되었다는 것을 알고 있습니다. 아마도이 기능은 주변에 없었습니다. 그러나 이제는 이렇게하는 것이 쉽습니다.

@Test
public void test_array_pass()
{
  List<String> actual = Arrays.asList("fee", "fi", "foe");
  List<String> expected = Arrays.asList("fee", "fi", "foe");

  assertThat(actual, is(expected));
  assertThat(actual, is(not(expected)));
}

hamcrest와 함께 최신 버전의 Junit을 설치 한 경우 다음 가져 오기를 추가하십시오.

import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;

http://junit.org/junit4/javadoc/latest/org/junit/Assert.html#assertThat(T, org.hamcrest.Matcher)

http://junit.org/junit4/javadoc/latest/org/hamcrest/CoreMatchers.html

http://junit.org/junit4/javadoc/latest/org/hamcrest/core/Is.html


3
System.out.println(actual == expected);false를 반환하지만 System.out.println(actual.equals(expected));true를 반환합니다.
메기

@Catfish 그래, 혼란스럽지 않아. 나는 matcher가 .equals(..)대신 사용하고 있음을 보여주고 있다고 생각 ==합니까?
djeikyb

2
assertEquals보다 나은 점은 무엇입니까?
Raedwald

1
어설 션이 실패하면 @Raedwald가 출력합니다. 차이를 수정하기 위해 나중에 다시 시도하겠습니다. hamcrest matchers는 자세한 실패 메시지를 생성 할 수 있습니다. junit이 assertEquals와 비슷한 장점을 단순히 오버로드 할 수 있습니다. 그러나 대부분 junit은 핵심 단위 테스트 기능을 제공하며 hamcrest는 객체 차이 설명 기 라이브러리를 제공합니다.
djeikyb

29

문자열로 변환하고 비교하지 마십시오. 이것은 성능에 좋지 않습니다. junit에는 Corematchers 안에 이에 대한 matcher가 있습니다.hasItems

List<Integer> yourList = Arrays.asList(1,2,3,4)    
assertThat(yourList, CoreMatchers.hasItems(1,2,3,4,5));

이것이 목록의 요소를 확인하는 더 좋은 방법입니다.


2
하나의 메모와 함께 선택한 답변이어야합니다. 또한 목록에 원하는 것 외에 다른 항목이 없는지 확인해야합니다. Assert.assertEquals(4,yourList.size());
yoni

또는 한 줄로 :assertThat(yourList.toArray(), arrayContainingInAnyOrder(1,2,3,4,5));
user1778602

3
"이것은 성능에 좋지 않습니다." 단위 테스트를 작성할 때 어느 정도의 성능을 고려해야 하는지 잘 모르겠습니다. 그러나 toString()버전을 통해 문자열을 비교 하는 것이 가장 좋은 방법은 아닙니다.
walen

21

이것은 JUnit 4.3 이하에 적합한 레거시 답변입니다. 최신 버전의 JUnit은 assertThat 메소드에 내장 된 읽기 가능한 실패 메시지를 포함합니다. 가능하면이 질문에 대한 다른 답변을 선호하십시오.

List<E> a = resultFromTest();
List<E> expected = Arrays.asList(new E(), new E(), ...);
assertTrue("Expected 'a' and 'expected' to be equal."+
            "\n  'a'        = "+a+
            "\n  'expected' = "+expected, 
            expected.equals(a));

@Paul이이 답변에 대한 그의 언급에서 언급했듯이, 두 개의 Lists는 같습니다.

지정된 객체도리스트 인 경우에만 두리스트의 크기가 동일하고 두리스트의 모든 해당 요소 쌍이 동일합니다. (두 요소 e1e2같으면 동일합니다 (e1==null ? e2==null : e1.equals(e2)).) 즉, 두 요소가 동일한 순서로 동일한 요소를 포함하는 경우 두 목록이 동일하게 정의됩니다. 이 정의는 equals 메소드가 List인터페이스의 다른 구현에서 올바르게 작동하도록합니다 .

인터페이스JavaDoc을List 참조하십시오 .


1
그래서 당신은 expect.equals (a)가 목록이 가지고있는 객체를 주장하는 것을 처리 할 것입니까?
Kamal

1
목록 javadoc에서 : 지정된 오브젝트와이 목록이 동일한 지 비교합니다. 지정된 객체도 목록이고 두 목록의 크기가 모두 같고 두 목록의 모든 해당 요소 쌍이 동일한 경우에만 true를 반환합니다. ((e1 == null? e2 == null : e1.equals (e2)) 인 경우 두 요소 e1 및 e2는 같습니다.) 즉, 동일한 순서로 동일한 요소를 포함하는 두 목록은 동일하도록 정의됩니다. . 이 정의는 equals 메소드가 다른 List 인터페이스 구현에서 올바르게 작동하도록합니다.
Paul McKenzie

1
이 아아는 도움이되지 않는 오류 메시지를 제공합니다. 루프를 수행하는 유틸리티 클래스를 작성하면 어떤 요소가 다른지 알 수 있습니다.
마이클 로이드 리 mlk

@ mlk 일 것입니다. 그러나 그런 일을위한 맞춤형 유틸리티 메소드를 작성하는 것을 망설입니다. 방금 편집 한 오류 메시지는 어떻습니까?
바트 키 어스

@mlk 각 요소를 테스트하기 위해 루프를 작성하는 것이 더 낫다는 것에 동의합니다. 목록에있는 개체 유형에 따라 다릅니다. 그들은, 문자열 경우 그냥 "A ="+ A해야 벌금을 말하지만, 그들은 복잡한 객체 (기타리스트, 또는 좋은의를 toString 구현이없는 뭔가를)하는 경우, 개별적으로 테스트하는 것이 더 쉬울 수 있습니다
매트 N

20

assertEquals(Object, Object)JUnit4에서 / JUnit을 5 assertThat(actual, is(expected));Hamcrest에서 단지 모두로 작동 다른 답변에서 제안 equals()하고 toString()비교 객체의 클래스 (깊이)에 대한 오버라이드된다.

어설 션의 동등성 테스트 equals()와 테스트 실패 메시지 toString()가 비교 된 개체 에 의존하기 때문에 중요 합니다.
들어 내장과 같은 클래스 String, Integer등등 ... 이러한 재정 등의 문제없이 모두 equals()toString(). 그래서 주장 완벽하게 유효 List<String>또는 List<Integer>assertEquals(Object,Object).
그리고이 문제에 대해 : equals()JUnit 테스트에서 어설 션을 쉽게 만들 수있을뿐만 아니라 객체 평등 측면에서 의미가 있기 때문에 클래스에서 재정의해야합니다 .
어설 션을 쉽게 만들려면 다른 방법이 있습니다.
모범 사례로 어설 션 / 매칭 라이브러리를 선호합니다.

다음은 AssertJ 솔루션입니다.

org.assertj.core.api.ListAssert.containsExactly() 그것은 당신이 필요로하는 것입니다 : 그것은 실제 그룹이 javadoc에 명시된 순서대로 주어진 값을 포함하고 다른 것을 포함하지 않는지 확인합니다.

Foo요소를 추가하고 얻을 수 있는 클래스를 가정하십시오 . 그에
대한 단위 테스트 Foo는 두 목록이 동일한 내용을 가지고 있다고 주장합니다.

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;

@Test
void add() throws Exception { 
   Foo foo = new Foo();
   foo.add("One", "Two", "Three");
   Assertions.assertThat(foo.getElements())
             .containsExactly("One", "Two", "Three");
}

AssertJ의 좋은 점은 List예상대로 선언하는 것이 불필요하다는 것입니다. 어설 션이 더 명확 하고 코드를 더 읽기 쉽게 만듭니다.

Assertions.assertThat(foo.getElements())
         .containsExactly("One", "Two", "Three");

그러나 어설 션 / 매치 라이브러리는 반드시 더 필요하기 때문에 필수입니다.
이제 가정 Foo 하지 않습니다 상점 String들하지만,이 Bar인스턴스를이야.
그것은 매우 일반적인 요구입니다. AssertJ를 사용하면 어설 션을 쉽게 작성할 수 있습니다. equals()/hashCode()JUnit 방식에 다음이 필요하지만 요소 클래스가 재정의되지 않더라도 목록 내용이 동일하다고 주장하는 것이 좋습니다 .

import org.assertj.core.api.Assertions;
import static org.assertj.core.groups.Tuple.tuple;
import org.junit.jupiter.api.Test;

@Test
void add() throws Exception {
    Foo foo = new Foo();
    foo.add(new Bar(1, "One"), new Bar(2, "Two"), new Bar(3, "Three"));
    Assertions.assertThat(foo.getElements())
              .extracting(Bar::getId, Bar::getName)
              .containsExactly(tuple(1, "One"),
                               tuple(2, "Two"),
                               tuple(3, "Three"));
}

7

요소의 순서에 신경 쓰지 않으면 ListAssert.assertEqualsjunit-addons를 권장 합니다.

링크 : http://junit-addons.sourceforge.net/

게으른 Maven 사용자의 경우 :

    <dependency>
        <groupId>junit-addons</groupId>
        <artifactId>junit-addons</artifactId>
        <version>1.4</version>
        <scope>test</scope>
    </dependency>

7
참고 : 요소의 순서에 신경 쓰지 않으면 목록이 아닌 집합 또는 컬렉션을 사용해야합니다.
Barett

11
나는 동의한다. 이 도서관은 거칠다. 지구상에서 ListAssert.assertEquals ()가 기본적으로 순서가없는 이유는 무엇입니까?
Ryan

5

junit에서 assertEquals 를 사용할 수 있습니다 .

import org.junit.Assert;   
import org.junit.Test;

    @Test
    public void test_array_pass()
    {
        List<String> actual = Arrays.asList("fee", "fi", "foe");
        List<String> expected = Arrays.asList("fee", "fi", "foe");
        Assert.assertEquals(actual,expected);
    }

요소의 순서가 다르면 오류를 반환합니다.

모델 객체 목록을 주장하는 경우 특정 모델의 equals 메서드를 재정의해야합니다.

    @Override
    public boolean equals(Object obj) {
        if (obj == this) {
            return true;
        }
        if (obj != null && obj instanceof ModelName) {
            ModelName other = (ModelName) obj;
            return this.getItem().equals(other.getItem()) ;
        }
        return false;
    }

4

배열 목록을 작성하지 않으려는 경우에도 시도 할 수 있습니다

@Test
public void test_array_pass()
{
  List<String> list = Arrays.asList("fee", "fi", "foe");
  Strint listToString = list.toString();
  Assert.assertTrue(listToString.contains("[fee, fi, foe]"));   // passes  
}

3
List<Integer> figureTypes = new ArrayList<Integer>(
                           Arrays.asList(
                                 1,
                                 2
                            ));

List<Integer> figureTypes2 = new ArrayList<Integer>(
                           Arrays.asList(
                                 1,
                                 2));

assertTrue(figureTypes .equals(figureTypes2 ));

1

바퀴를 재발 명하지 마십시오!

이를 위해 Google 코드 라이브러리가 있습니다 : Hamcrest

[Hamcrest] 다른 프레임 워크에서 사용될 '일치'규칙을 선언적으로 정의 할 수있는 matcher 객체 (제약 또는 조건 자라고도 함)의 라이브러리를 제공합니다. 일반적인 시나리오에는 프레임 워크 테스트, 모의 라이브러리 및 UI 유효성 검사 규칙이 포함됩니다.


0

이미이 문제를 해결할 수있는 옵션이 많이 있다는 것을 알고 있지만 두 가지 목록을 모두 주문 하려면 다음을 수행하십시오 .

assertTrue(result.containsAll(expected) && expected.containsAll(result))

주문이 일치하지 않으면 실패하지 않습니까 ??
iec2011007

0

assertEquals(expected, result);나를 위해 작동합니다. 이 함수는 두 개의 객체를 가져 오기 때문에 무엇이든 전달할 수 있습니다.

public static void assertEquals(Object expected, Object actual) {
    AssertEquals.assertEquals(expected, actual);
}

-1

위의 모든 대답이 두 객체 목록을 비교하기위한 정확한 솔루션을 제공하지는 않습니다. 위의 접근 방식의 대부분은 다음의 비교 제한에만 도움이 될 수 있습니다.-크기 비교-참조 비교

그러나 동일한 크기의 객체 목록과 객체 수준에서 다른 데이터를 가지고 있다면이 비교 방법은 도움이되지 않습니다.

다음 접근법은 사용자 정의 객체에서 equals 및 hashcode 메서드를 재정의하는 경우 완벽하게 작동한다고 생각합니다.

나는 equals와 hashcode를 재정의하기 위해 Xstream lib를 사용 했지만 승리 한 논리 / 비교로 equals와 hashcode를 재정의 할 수 있습니다.

다음은 참고 용 예입니다.

    import com.thoughtworks.xstream.XStream;

    import java.text.ParseException;
    import java.util.ArrayList;
    import java.util.List;

    class TestClass {
      private String name;
      private String id;

      public void setName(String value) {
        this.name = value;
      }

      public String getName() {
        return this.name;
      }

      public String getId() {
        return id;
      }

      public void setId(String id) {
        this.id = id;
      }

      /**
       * @see java.lang.Object#equals(java.lang.Object)
       */
      @Override
      public boolean equals(Object o) {
        XStream xstream = new XStream();
        String oxml = xstream.toXML(o);
        String myxml = xstream.toXML(this);

        return myxml.equals(oxml);
      }

      /**
       * @see java.lang.Object#hashCode()
       */
      @Override
      public int hashCode() {
        XStream xstream = new XStream();
        String myxml = xstream.toXML(this);
        return myxml.hashCode();
      }
    }

    public class XstreamCompareTest {
      public static void main(String[] args) throws ParseException {
      checkObjectEquals();
}

      private static void checkObjectEquals() {
        List<TestClass> testList1 = new ArrayList<TestClass>();
        TestClass tObj1 = new TestClass();
        tObj1.setId("test3");
        tObj1.setName("testname3");
        testList1.add(tObj1);

        TestClass tObj2 = new TestClass();
        tObj2.setId("test2");
        tObj2.setName("testname2");
        testList1.add(tObj2);

        testList1.sort((TestClass t1, TestClass t2) -> t1.getId().compareTo(t2.getId()));

        List<TestClass> testList2 = new ArrayList<TestClass>();
        TestClass tObj3 = new TestClass();
        tObj3.setId("test3");
        tObj3.setName("testname3");
        testList2.add(tObj3);

        TestClass tObj4 = new TestClass();
        tObj4.setId("test2");
        tObj4.setName("testname2");
        testList2.add(tObj4);

        testList2.sort((TestClass t1, TestClass t2) -> t1.getId().compareTo(t2.getId()));

        if (isNotMatch(testList1, testList2)) {
          System.out.println("The list are not matched");
        } else {
          System.out.println("The list are matched");
        }

      }

      private static boolean isNotMatch(List<TestClass> clist1, List<TestClass> clist2) {
        return clist1.size() != clist2.size() || !clist1.equals(clist2);
      }
    }

가장 중요한 것은 동일한 객체 검사에 필드를 포함하지 않으려면 주석 (@XStreamOmitField)으로 필드를 무시할 수 있다는 것입니다. 이와 같이 구성 할 수있는 많은 주석이 있으므로이 lib의 주석에 대해 자세히 살펴보십시오.

이 답변이 두 객체 목록을 비교하는 올바른 방법을 식별하는 데 시간을 절약 할 것이라고 확신합니다. :). 이것에 문제가 있으면 의견을 말하십시오.

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