Сравнение коллекций в Java с помощью Hamcrest matchers
Быстрый ответ
Для проверки наличия идентичных элементов в коллекциях, не принимая во внимание их порядок, используйте метод containsInAnyOrder
из библиотеки Hamcrest:
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsInAnyOrder;
// Сравниваем наборы фруктов: порядок неважен, главное — это сами фрукты!
assertThat(Arrays.asList("яблоко", "банан"), containsInAnyOrder("банан", "яблоко"));
В случаях, когда порядок элементов имеет значение, следует применять contains
:
import static org.hamcrest.Matchers.contains;
// Яблоки идут перед бананами, и именно так и должно быть по алфавиту.
assertThat(Arrays.asList("яблоко", "банан"), contains("яблоко", "банан"));
Эти примеры демонстрируют, как можно использовать Hamcrest matchers для сравнения коллекций.
Сопоставление списков на полное совпадение
Если требуется подтвердить полное соответствие двух списков, можно выполнить следующее:
import static org.junit.Assert.assertEquals;
// Подтверждаем, что яблоки всегда идут перед бананами, как и полагает природа
assertEquals(Arrays.asList("яблоко", "банан"), Arrays.asList("яблоко", "банан"));
Проверка типов: незаметный герой кода
Убедитесь, что тип списка соответствует типу, ожидаемому в matchers:
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); // Незаметно и элегантно, как работа самого агента.
Визуализация
Представьте каждую коллекцию как уникальный набор деталей пазла (🧩):
Коллекция А: [🧩1, 🧩2, 🧩3]
Коллекция B: [🧩3, 🧩4, 🧩5]
Наша цель — найти соответствие между этими двуми коллекциями с помощью Hamcrest:
Matchers.containsInAnyOrder(КоллекцияА, КоллекцияB);
Визуально проверка может выглядеть следующим образом:
🧩 Есть соответствие? 🧩
А: [🧩1, 🧩2, ✅🧩3]
B: [✅🧩3, 🧩4, 🧩5]
✅ отмечает найденные совпадения, а 🧩 показывает уникальные элементы. С помощью Hamcrest порядок элементов не важен.
Поиск «иголки в стоге сена»
В поисках одного элемента
Используйте hasItem
, чтобы проверить наличие одного конкретного элемента:
import static org.hamcrest.Matchers.hasItem;
assertThat(Arrays.asList("яблоко", "банан"), hasItem("яблоко")); // нашли наше "запретное" яблоко
Поиск нескольких элементов
Для проверки нескольких элементов используйте hasItems
:
import static org.hamcrest.Matchers.hasItems;
assertThat(Arrays.asList("яблоко", "банан", "вишня"), hasItems("вишня", "банан")); // больше фруктов, отлично!
Комбинируем матчеры
Матчеры можно сочетать, используя allOf
:
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
:
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
.
Внимание к деталям
Преобразование списков в массивы для удобства сравнения
Если удобнее сравнивать элементы после их преобразования из списка в массив, сделайте следующее:
String[] expectedArray = {"яблоко", "банан"};
List<String> actualList = Arrays.asList("банан", "яблоко");
assertThat(actualList, containsInAnyOrder(expectedArray)); // снова фрукты, теперь в виде массива!
Избегаем подводных камней!
Соблюдая типобезопасность и правильное использование matchers, вы избавляетесь от странных, но сложных в устранении ошибок.
Читаемые утверждения: все под контролем.
Чтобы ваши утверждения были максимально понятными, проведите статический импорт containsInAnyOrder
.
Полезные материалы
- Java Hamcrest — официальная документация Hamcrest.
- Руководство пользователя JUnit 5 — всё, что нужно знать о тестировании в JUnit 5.
- AssertJ – библиотека "плавных" утверждений java — библиотека утверждений AssertJ, альтернатива Hamcrest.
- Matchers (Hamcrest) — официальная Javadoc для класса Matcher.
- GitHub – hamcrest/JavaHamcrest — исходный код и примеры Hamcrest matchers.
- Использование Hamcrest для тестирования – учебное пособие — учебное руководство по работе с Hamcrest в тестах JUnit.