Рубрики
Без рубрики

Утверждение двух списков для равенства Игнорирование порядка в Java

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

Автор оригинала: baeldung.

1. Обзор

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

2. Настройка

Согласно документации List#equals Java, два списка равны, если они содержат одни и те же элементы в одном и том же порядке. Поэтому мы не можем просто использовать метод equals , как мы хотим сделать агностическое сравнение.

На протяжении всего этого урока мы будем использовать эти три списка в качестве примеров входных данных для наших тестов:

List first = Arrays.asList(1, 3, 4, 6, 8);
List second = Arrays.asList(8, 1, 6, 3, 4);
List third = Arrays.asList(1, 3, 3, 6, 6);

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

3. Использование JUnit

JUnit-это хорошо известный фреймворк, используемый для модульного тестирования в экосистеме Java.

Мы можем использовать приведенную ниже логику для сравнения равенства двух списков с помощью методов assertTrue и assertFalse.

Здесь мы проверяем размер обоих списков и проверяем, содержит ли первый список все элементы второго списка, и наоборот. Хотя это решение работает, оно не очень читабельно. Итак, теперь давайте рассмотрим некоторые альтернативы:

@Test
public void whenTestingForOrderAgnosticEquality_ShouldBeTrue() {
    assertTrue(first.size() == second.size() && first.containsAll(second) && second.containsAll(first));
}

В этом первом тесте сравнивается размер обоих списков, прежде чем мы проверим, одинаковы ли элементы в обоих списках. Поскольку оба эти условия возвращают true, наш тест пройдет.

Давайте теперь посмотрим на провальный тест:

@Test
public void whenTestingForOrderAgnosticEquality_ShouldBeFalse() {
    assertFalse(first.size() == third.size() && first.containsAll(third) && third.containsAll(first));
}

Напротив, в этой версии теста, хотя размер обоих списков одинаков, все элементы не совпадают.

4. Использование AssertJ

AssertJ-это библиотека с открытым исходным кодом, управляемая сообществом, используемая для написания беглых и богатых утверждений в тестах Java.

Чтобы использовать его в вашем проекте maven, давайте добавим зависимость assertj-core в pom.xml файл:


    org.assertj
    assertj-core
    3.16.1

Давайте напишем тест для сравнения равенства двух экземпляров списка одного и того же элемента и одного и того же размера:

@Test
void whenTestingForOrderAgnosticEqualityBothList_ShouldBeEqual() {
    assertThat(first).hasSameElementsAs(second);
}

В этом примере мы проверяем, что first содержит все элементы данной итерации и ничего больше, в любом порядке. Основным ограничением этого подхода является то, что имеет те же элементы, что и метод игнорирует дубликаты.

Давайте посмотрим на это на практике, чтобы понять, что мы имеем в виду:

@Test
void whenTestingForOrderAgnosticEqualityBothList_ShouldNotBeEqual() {
    List a = Arrays.asList("a", "a", "b", "c");
    List b = Arrays.asList("a", "b", "c");
    assertThat(a).hasSameElementsAs(b);
}

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

assertThat(a).hasSize(b.size()).hasSameElementsAs(b);

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

5. Использование Hamcrest

Если мы уже используем Hamcrest или хотим использовать его для написания модульных тестов, вот как мы можем использовать метод Matchers#containsInAnyOrder для сравнения порядка агностиков.

Чтобы использовать Hamcrest в нашем проекте maven, давайте добавим зависимость hamcrest-all в pom.xml файл:


    org.hamcrest
    hamcrest-all
    1.3

Давайте посмотрим на тест:

@Test
public void whenTestingForOrderAgnosticEquality_ShouldBeEqual() {
    assertThat(first, Matchers.containsInAnyOrder(second.toArray()));
}

Здесь метод containsInAnyOrder создает агностический сопоставитель порядка для Iterables , который выполняет сопоставление с исследуемыми Iterable элементами. Этот тест сопоставляет элементы двух списков, игнорируя порядок элементов в списке.

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

6. Использование Apache Commons

Еще одна библиотека или фреймворк, помимо JUnit, Hamcrest или AssertJ, которые мы можем использовать, – это Apache CollectionUtils . Он предоставляет полезные методы для общих операций, которые охватывают широкий спектр вариантов использования и помогают нам избежать написания шаблонного кода.

Чтобы использовать его в вашем проекте maven, давайте добавим зависимость commons-collections4 в pom.xml файл:


    org.apache.commons
    commons-collections4
    4.4

Вот тест с использованием CollectionUtils :

@Test
public void whenTestingForOrderAgnosticEquality_ShouldBeTrueIfEqualOtherwiseFalse() {
    assertTrue(CollectionUtils.isEqualCollection(first, second));
    assertFalse(CollectionUtils.isEqualCollection(first, third));
}

Метод isEqualCollection возвращает true , если данные коллекции содержат точно такие же элементы с одинаковыми мощностями . В противном случае он возвращает false .

7. Заключение

В этой статье мы рассмотрели, как проверить равенство двух экземпляров List , где элементы обоих списков упорядочены по-разному.

Все эти примеры можно найти на GitHub .