Сравнение коллекций в Java с помощью Hamcrest matchers

Пройдите тест, узнайте какой профессии подходите

Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

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

Java
Скопировать код
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsInAnyOrder;

// Сравниваем наборы фруктов: порядок неважен, главное — это сами фрукты!
assertThat(Arrays.asList("яблоко", "банан"), containsInAnyOrder("банан", "яблоко"));

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

Java
Скопировать код
import static org.hamcrest.Matchers.contains;

// Яблоки идут перед бананами, и именно так и должно быть по алфавиту.
assertThat(Arrays.asList("яблоко", "банан"), contains("яблоко", "банан"));

Эти примеры демонстрируют, как можно использовать Hamcrest matchers для сравнения коллекций.

Кинга Идем в IT: пошаговый план для смены профессии

Сопоставление списков на полное совпадение

Если требуется подтвердить полное соответствие двух списков, можно выполнить следующее:

Java
Скопировать код
import static org.junit.Assert.assertEquals;

// Подтверждаем, что яблоки всегда идут перед бананами, как и полагает природа
assertEquals(Arrays.asList("яблоко", "банан"), Arrays.asList("яблоко", "банан"));

Проверка типов: незаметный герой кода

Убедитесь, что тип списка соответствует типу, ожидаемому в matchers:

Java
Скопировать код
List<Agent> agentList = Arrays.asList(new Agent("007"), new Agent("006"));
Matcher<Iterable<? extends Agent>> matcher = containsInAnyOrder(new Agent("006"), new Agent("007"));
assertThat(agentList, matcher); // Незаметно и элегантно, как работа самого агента.

Визуализация

Представьте каждую коллекцию как уникальный набор деталей пазла (🧩):

Markdown
Скопировать код
Коллекция А: [🧩1, 🧩2, 🧩3]
Коллекция B: [🧩3, 🧩4, 🧩5]

Наша цель — найти соответствие между этими двуми коллекциями с помощью Hamcrest:

Markdown
Скопировать код
Matchers.containsInAnyOrder(КоллекцияА, КоллекцияB);

Визуально проверка может выглядеть следующим образом:

Markdown
Скопировать код
🧩 Есть соответствие? 🧩
А: [🧩1, 🧩2, ✅🧩3]
B: [✅🧩3, 🧩4, 🧩5]

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

Поиск «иголки в стоге сена»

В поисках одного элемента

Используйте hasItem, чтобы проверить наличие одного конкретного элемента:

Java
Скопировать код
import static org.hamcrest.Matchers.hasItem;

assertThat(Arrays.asList("яблоко", "банан"), hasItem("яблоко")); // нашли наше "запретное" яблоко

Поиск нескольких элементов

Для проверки нескольких элементов используйте hasItems:

Java
Скопировать код
import static org.hamcrest.Matchers.hasItems;

assertThat(Arrays.asList("яблоко", "банан", "вишня"), hasItems("вишня", "банан")); // больше фруктов, отлично!

Комбинируем матчеры

Матчеры можно сочетать, используя allOf:

Java
Скопировать код
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.everyItem;
import static org.hamcrest.Matchers.greaterThan;

// Проверяем, присутствует ли в списке число 2 и каждый элемент больше нуля, ведь мы за позитивное мышление
assertThat(Arrays.asList(1, 2, 3), allOf(hasItem(2), everyItem(greaterThan(0))));

Матчеры свойств — незаслуженно обделённые вниманием герои

Для сравнения свойств объектов в коллекциях используйте hasProperty:

Java
Скопировать код
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.hasProperty;

List<Person> persons = Arrays.asList(new Person("Джон", 30), new Person("Джейн", 25));
assertThat(persons, hasItem(hasProperty("name", is("Джейн")))); // Нашли Джейн.

Не забудьте импортировать org.hamcrest.Matchers.is.

Внимание к деталям

Преобразование списков в массивы для удобства сравнения

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

Java
Скопировать код
String[] expectedArray = {"яблоко", "банан"};
List<String> actualList = Arrays.asList("банан", "яблоко");
assertThat(actualList, containsInAnyOrder(expectedArray)); // снова фрукты, теперь в виде массива!

Избегаем подводных камней!

Соблюдая типобезопасность и правильное использование matchers, вы избавляетесь от странных, но сложных в устранении ошибок.

Читаемые утверждения: все под контролем.

Чтобы ваши утверждения были максимально понятными, проведите статический импорт containsInAnyOrder.

Полезные материалы

  1. Java Hamcrest — официальная документация Hamcrest.
  2. Руководство пользователя JUnit 5 — всё, что нужно знать о тестировании в JUnit 5.
  3. AssertJ – библиотека "плавных" утверждений java — библиотека утверждений AssertJ, альтернатива Hamcrest.
  4. Matchers (Hamcrest)официальная Javadoc для класса Matcher.
  5. GitHub – hamcrest/JavaHamcrest — исходный код и примеры Hamcrest matchers.
  6. Использование Hamcrest для тестирования – учебное пособие — учебное руководство по работе с Hamcrest в тестах JUnit.