Подтвердить что ты не робот

Как проверить JUnit, что два списка <E> содержат одни и те же элементы в одном порядке?

Контекст

Я пишу простой JUnit тест для класса MyObject.

A MyObject может быть создан из статического метода factory, который принимает varargs String.

MyObject.ofComponents("Uno", "Dos", "Tres");

В любой момент существования MyObject клиенты могут проверять параметры, которые он создал, в форме Список <E> , с помощью метода .getComponents().

myObject.ofComponents(); // -> List<String>: { "Uno", "Dos", "Tres" }

Другими словами, a MyObject запоминает и предоставляет список параметров, которые привели его к существованию. Подробнее об этом контракте:

  • Порядок getComponents будет таким же, как тот, который выбран для создания объекта
  • Дублировать последующие String. и сохраняются в порядке
  • Поведение на null - undefined (другой код гарантирует, что null не получит factory)
  • Невозможно изменить список компонентов после создания объекта

Я пишу простой тест, который создает MyObject из списка String и проверяет, может ли он вернуть тот же список через .getComponents(). Я делаю это немедленно, но это должно произойти на расстоянии в реалистичном пути кода.

код

Здесь моя попытка:


List<String> argumentComponents = Lists.newArrayList("One", "Two", "Three");
List<String> returnedComponents =
    MyObject.ofComponents(
        argumentComponents.toArray(new String[argumentComponents.size()]))
        .getComponents();
assertTrue(Iterables.elementsEqual(argumentComponents, returnedComponents));

Вопрос

  • Google Guava Iterables.elementsEqual() лучший способ, если у меня есть библиотека в моем пути сборки, чтобы сравнить эти два списка? это то, о чем я мучился; должен ли я использовать этот вспомогательный метод, который проходит через Iterable <E> . check размер, а затем повторить запуск .equals().. или любой другой метод, который предлагает поиск в Интернете? каков канонический способ сравнения списков для модульных тестов?

Дополнительная информация, которую я хотел бы получить

  • Является ли метод испытаний разработанным разумно? Я не эксперт в JUnit!
  • Является .toArray() лучшим способом преобразования List <E> к varargs E?
4b9b3361

Ответ 1

Я предпочитаю использовать Hamcrest, потому что он дает намного лучший выход в случае сбоя

Assert.assertThat(listUnderTest, 
       IsIterableContainingInOrder.contains(expectedList.toArray()));

Вместо сообщения

expected true, got false

он сообщит

expected List containing "1, 2, 3, ..." got list containing "4, 6, 2, ..."

IsIterableContainingInOrder.contain

Hamcrest

Согласно Javadoc:

Создает совпадение для Iterables, которое соответствует, когда один проход по проверенному Iterable дает ряд элементов, каждый из которых логически равен соответствующему элементу в указанных элементах. Для положительного совпадения проверенная итерация должна быть такой же длины, как количество указанных элементов

Итак, listUnderTest должно иметь одинаковое количество элементов, и каждый элемент должен соответствовать ожидаемым значениям в порядке.

Ответ 2

Почему бы просто не использовать List#equals?

assertEquals(argumentComponents, imapPathComponents);

Контракт List#equals:

два списка определены равными, если они содержат одни и те же элементы в одном порядке.

Ответ 3

Метод equals() в вашей реализации List должен делать элементарное сравнение, поэтому

assertEquals(argumentComponents, returnedComponents);

намного проще.

Ответ 4

org.junit.Assert.assertEquals() и org.junit.Assert.assertArrayEquals() выполните задание.

Чтобы избежать следующих вопросов: Если вы хотите игнорировать заказ, установите все элементы для установки, а затем сравните: Assert.assertEquals(new HashSet<String>(one), new HashSet<String>(two))

Если вы просто хотите игнорировать дубликаты, но сохраните список заказов, который вы перечисляете с помощью LinkedHashSet.

Еще один совет. Трюк Assert.assertEquals(new HashSet<String>(one), new HashSet<String>(two)) работает нормально, пока сравнение не завершится. В этом случае оно отображает сообщение об ошибке с строковыми представлениями ваших наборов, которые могут сбивать с толку, потому что порядок в наборе почти не предсказуем (по крайней мере для сложных объектов). Итак, трюк, который я нашел, - это обернуть коллекцию отсортированным набором вместо HashSet. Вы можете использовать TreeSet с пользовательским компаратором.

Ответ 5

Для отличной читаемости кода Fest Assertions имеет приятную поддержку утверждение списки

Итак, в этом случае что-то вроде:

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

Или сделать ожидаемый список массивом, но я предпочитаю этот подход, потому что он более понятен.

Assertions.assertThat(returnedComponents).containsExactly(argumentComponents.toArray());

Ответ 6

  • Мой ответ о том, лучший ли Iterables.elementsEqual:

Iterables.elementsEqual достаточно для сравнения 2 List s.

Iterables.elementsEqual используется в более общих сценариях, он принимает более общие типы: Iterable. То есть, вы даже можете сравнить List с Set. (по порядку итерации, это важно)

Конечно, ArrayList и LinkedList define equals довольно хорошо, вы могли бы называть equals напрямую. Хотя, когда вы используете не правильно определенный список, Iterables.elementsEqual - лучший выбор. Следует отметить одно: Iterables.elementsEqual не принимает null

  • Преобразование списка в массив: Iterables.toArray является более простым.

  • Для unit test я рекомендую добавить пустой список в тестовый файл.