Hamcrest сравнить коллекции


114

Я пытаюсь сравнить 2 списка:

assertThat(actual.getList(), is(Matchers.containsInAnyOrder(expectedList)));

Но идея

java: no suitable method found for assertThat(java.util.List<Agent>,org.hamcrest.Matcher<java.lang.Iterable<? extends model.Agents>>)
method org.junit.Assert.<T>assertThat(T,org.hamcrest.Matcher<T>) is not applicable
  (no instance(s) of type variable(s) T exist so that argument type org.hamcrest.Matcher<java.lang.Iterable<? extends model.Agents>> conforms to formal parameter type org.hamcrest.Matcher<T>)
method org.junit.Assert.<T>assertThat(java.lang.String,T,org.hamcrest.Matcher<T>) is not applicable
  (cannot instantiate from arguments because actual and formal argument lists differ in length)

Как мне это написать?

Ответы:


161

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

assertEquals(expectedList, actual.getList());

Если вы действительно намереваетесь выполнить сравнение без containsInAnyOrderучета порядка, вы можете вызвать метод varargs и напрямую указать значения:

assertThat(actual.getList(), containsInAnyOrder("item1", "item2"));

(Предполагая, что ваш список состоит из String, а не Agentдля этого примера.)

Если вы действительно хотите вызвать тот же метод с содержимым List:

assertThat(actual.getList(), containsInAnyOrder(expectedList.toArray(new String[expectedList.size()]));

Без этого вы вызываете метод с одним аргументом и создаете объект, Matcherкоторый должен соответствовать, Iterableгде каждый элемент является List. Это не может использоваться для сопоставления List.

То есть вы не можете сопоставить a List<Agent>с a Matcher<Iterable<List<Agent>>, что и пытается сделать ваш код.


+1 за «Если вы действительно хотите вызвать тот же метод с содержимым списка». К сожалению, я сам не смог решить эту проблему. Тем более, что есть конструктор, который принимает коллекцию.
Эйяд Эбрагим

3
@ Тим Не совсем; containsInAnyOrderтребует наличия всех элементов, поэтому первое утверждение не будет выполнено. Посмотрите hasItems, хотите ли вы проверить наличие хотя бы этих элементов.
Джо

4
Если вы используете containsInAnyOrder, вы должны сначала убедиться, что оба списка имеют одинаковый размер ... Если он actual.getList()содержит "item1", "item3", "item2", тест пройдет, и, возможно, вы захотите убедиться, что он содержит только перечисленные элементы ... В этом случае вы можете использовать assertThat(actual.getList().size(), equalTo(2));перед containsInAnyOrder, таким образом вы убедитесь, что оба списка имеют одинаковое содержимое.
Martin

1
@ Мартин, о котором ты думаешь hasItems. Дополнительная проверка здесь не требуется. См. Комментарий к Тиму выше, а также Чем отличаются hasItems, contains и containsInAnyOrder в Hamcrest?
Джо

1
Пользователи Kotlin : не забудьте добавить оператор распространения ( *expectedList.toTypedArray()) при передаче массива как varargs!
Джеймс Боуман

63
List<Long> actual = Arrays.asList(1L, 2L);
List<Long> expected = Arrays.asList(2L, 1L);
assertThat(actual, containsInAnyOrder(expected.toArray()));

Укороченная версия ответа @Jo без лишних параметров.


28

Чтобы дополнить ответ @Jo:

Hamcrest предоставляет вам три основных метода сопоставления со списком:

contains Проверяет соответствие всех элементов в порядке подсчета, если в списке больше или меньше элементов, это не удастся

containsInAnyOrder Проверяет соответствие всех элементов и не имеет значения порядок, если в списке больше или меньше элементов, не удастся

hasItems Проверяет только указанные объекты, неважно, есть ли в списке больше

hasItem Проверяет только один объект, неважно, есть ли в списке больше

Все они могут получать список объектов и использовать equalsметод сравнения или могут быть смешаны с другими сопоставителями, такими как упомянутый @borjab:

assertThat(myList , contains(allOf(hasProperty("id", is(7L)), 
                                   hasProperty("name", is("testName1")),
                                   hasProperty("description", is("testDesc1"))),
                             allOf(hasProperty("id", is(11L)), 
                                   hasProperty("name", is("testName2")),
                                   hasProperty("description", is("testDesc2")))));

http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html#contains (E ...) http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html #containsInAnyOrder (java.util.Collection) http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html#hasItems (T ...)


Отличное решение, если элементы списка не примитивного типа.
Станислав Цепа

Есть ли безопасный способ сделать это?
andresp

15

С существующими библиотеками Hamcrest (начиная с версии 2.0.0.0) вы вынуждены использовать метод Collection.toArray () в своей коллекции, чтобы использовать containsInAnyOrder Matcher. Гораздо лучше было бы добавить это как отдельный метод в org.hamcrest.Matchers:

public static <T> org.hamcrest.Matcher<java.lang.Iterable<? extends T>> containsInAnyOrder(Collection<T> items) {
    return org.hamcrest.collection.IsIterableContainingInAnyOrder.<T>containsInAnyOrder((T[]) items.toArray());
}

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


2
Отлично, я воспользуюсь этим помощником. Сообщение assert здесь более информативно: оно называет недостающие элементы один за другим, а не просто: список должен быть elem1, elem2, .. elem99, но у меня есть elem1, elem2, ..., elem98 - удачи поиск пропавшего.
pihentagy 07

3

Убедитесь, что Objects в вашем списке equals()определены на них. затем

    assertThat(generatedList,is(equalTo(expectedList)));

работает.


1

Для списка объектов вам может понадобиться что-то вроде этого:

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.beans.HasPropertyWithValue.hasProperty;
import static org.hamcrest.Matchers.is;

@Test
@SuppressWarnings("unchecked")
public void test_returnsList(){

    arrange();
  
    List<MyBean> myList = act();
    
    assertThat(myList , contains(allOf(hasProperty("id",          is(7L)), 
                                       hasProperty("name",        is("testName1")),
                                       hasProperty("description", is("testDesc1"))),
                                 allOf(hasProperty("id",          is(11L)), 
                                       hasProperty("name",        is("testName2")),
                                       hasProperty("description", is("testDesc2")))));
}

Используйте containsInAnyOrder, если не хотите проверять порядок объектов.

PS Мы будем очень благодарны за любую помощь, чтобы избежать предупреждения, которое подавляется.


-3

Чтобы сравнить два списка с сохраненным порядком, используйте

assertThat(actualList, contains("item1","item2"));

Это не отвечает на вопрос.
kamczak

Частично это так.
rvazquezglez 02

@rvazquezglez Что ты имеешь в виду? Почему ты это сказал? Результат метода соответствует моему окружению.
niaomingjian

@niaomingjian Код проверяет, что actualListсодержит элементы внутри containsсопоставителя, который завершится ошибкой, если элементы находятся в другом порядке, и также потерпит неудачу, если он содержит больше элементов или отсутствует один.
rvazquezglez

@rvazquezglez, поэтому цель кода - проверить точное равенство (одинаковые длины, значения и порядок) в двух списках, верно?
niaomingjian
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.