Утверждать о списке в Junit - PullRequest
141 голосов
/ 13 июля 2010

Как сделать утверждения о списке в JUnit контрольном примере?Не только размер списка, но и содержимое списка.

Ответы [ 10 ]

144 голосов
/ 19 мая 2012

Я понимаю, что об этом спросили пару лет назад, возможно, этой функции тогда не было. Но теперь это легко сделать:

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

Если у вас установлена ​​последняя версия Junit с Hamcrest, просто добавьте следующий импорт:

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

25 голосов
/ 17 октября 2014

Не преобразовывать в строку и сравнить. Это не хорошо для исполнения. В джуните, внутри Corematchers, есть подходящее средство для этого => hasItems

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

Это лучший из известных мне способов проверки элементов в списке.

19 голосов
/ 13 июля 2010

Это устаревший ответ, подходящий для 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 упомянул в своем комментарии к этому ответу, два List s равны:

тогда и только тогда, когда указанный объект также является списком, оба списка имеют одинаковый размер, и все соответствующие пары элементов в этих двух списках равны. (Два элемента e1 и e2 равны, если (e1==null ? e2==null : e1.equals(e2)).) Другими словами, два списка определены как равные, если они содержат одинаковые элементы в одинаковом порядке. Это определение обеспечивает правильную работу метода equals в различных реализациях интерфейса List.

См. JavaDocs интерфейса List .

7 голосов
/ 12 августа 2018

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

Но библиотеки Assertion / matcher обязательны, потому что они действительно будут дальше.
Предположим теперь, что 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 голосов
/ 30 мая 2012

Если вам не важен порядок элементов, я рекомендую ListAssert.assertEquals в junit-аддонах.

Ссылка: http://junit -addons.sourceforge.net /

Для ленивых пользователей Maven:

    <dependency>
        <groupId>junit-addons</groupId>
        <artifactId>junit-addons</artifactId>
        <version>1.4</version>
        <scope>test</scope>
    </dependency>
3 голосов
/ 24 августа 2015
List<Integer> figureTypes = new ArrayList<Integer>(
                           Arrays.asList(
                                 1,
                                 2
                            ));

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

assertTrue(figureTypes .equals(figureTypes2 ));
3 голосов
/ 12 августа 2013

если вы не хотите создавать список массивов, вы можете попробовать это также

@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  
}
2 голосов
/ 06 апреля 2018

Вы можете использовать assertEquals в junit.

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;
    }
1 голос
/ 05 июня 2013

Не изобретайте велосипед!

Есть библиотека Google Code, которая сделает это за вас: Hamcrest

[Hamcrest] Предоставляет библиотекуобъекты-сопоставители (также известные как ограничения или предикаты), позволяющие декларативно определять правила «соответствия» и использовать их в других средах.Типичные сценарии включают каркасы тестирования, библиотеки-макеты и правила проверки пользовательского интерфейса.

0 голосов
/ 02 марта 2018

Не знаю, все приведенные выше ответы дают точное решение для сравнения двух списков объектов.Большинство из вышеперечисленных подходов могут быть полезны только в следующем ограничении сравнений - Сравнение размеров - Сравнение ссылок

Но если у нас есть списки объектов одинакового размера и разные данные на уровне объектов, тогда эти подходы сравнения не помогут.

Я думаю, что следующий подход будет отлично работать с переопределением equals и методом хэш-кода для пользовательского объекта.

Я использовал 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), если вы не хотите включать какие-либо поля в одинаковую проверку объектов.Существует множество подобных аннотаций для настройки, поэтому внимательно изучите аннотации этой библиотеки.

Я уверен, что этот ответ сэкономит ваше время, чтобы определить правильный подход для сравнения двух списков объектов :).Пожалуйста, прокомментируйте, если вы видите какие-либо проблемы по этому вопросу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...