it-roy-ru.com

Утверждение о Списке в Junit

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

127
Kamal

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

@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

135
djeikyb

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

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

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

19
Bart Kiers

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

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

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

18
Andre Fonseca

Если вам не важен порядок элементов, я рекомендую ListAssert.assertEquals в junit-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
Viktor Nordling

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 хранит не Strings, а экземпляры Bars.
Это очень распространенная потребность. С 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"));
}
4
davidxxx

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

@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
Arun Pratap Singh
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
Ruslan Gafiullin

Вы можете использовать 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;
    }
2
Dhyan Mohandas

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

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

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

1
Bohemian

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

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

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

Я использовал Xstream lib для переопределения equals и hashcode, но мы можем переопределить 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);
      }
    }

Самое главное, что вы можете игнорировать поля с помощью Annotation (@XStreamOmitField), если вы не хотите включать какие-либо поля в одинаковую проверку объектов. Существует множество подобных аннотаций для настройки, поэтому внимательно изучите аннотации этой библиотеки.

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

0
Ganesa Vijayakumar