Контекст
Я пишу простой 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?
Ответ 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