Java Hamcrest: коллекция содержит элемент типа

Я хотел бы утверждать, что List<Achievement> содержит член типа TestAchievement.

Вот мое утверждение:

List<Achievement> achievements; // Populated elsewhere
assertThat(achievements,hasItem(isA(TestAchievement.class)));

Это не компилируется, сообщая об ошибке:

Метод assertThat(T, Matcher) в типе Assert неприменим для аргументов (List, Matcher‹Iterable‹TestAchievement>>)

Каков правильный синтаксис для этого типа утверждения с использованием Hamcrest?


person Marty Pitt    schedule 13.02.2011    source источник


Ответы (7)


Спасибо за помощь.

Сообщения здесь предполагали, что это был дефект с Hamcrest, поэтому я направился на сайт hacmrest, чтобы зарегистрировать ошибку, когда я обнаружил, что объявление зависимости mvn/ivy, которое я использовал, устарело, что дало мне старую версию Хэмкрест.

Эта ошибка существует в версии 1.1, которая является последней, если она объявлена ​​с использованием

<dependency org="org.hamcrest" name="hamcrest-all" rev="1.1">

Однако правильное объявление зависимости:

<dependency org="org.hamcrest" name="hamcrest-library" rev="1.3.RC2"/>

Обновление до этого решило проблему. Синтаксис, используемый в моем тесте:

 assertThat(achievements, hasItem(isA(TestAchievement.class)));
person Marty Pitt    schedule 13.02.2011
comment
Однажды я потратил почти неделю на то, чтобы ломать голову над той же самой проблемой ошибочного объявления в коде библиотеки hamcrest, прежде чем наконец наткнулся на исправленную обновленную версию. Просто орехи! Все не должно быть таким сложным. - person tchrist; 13.02.2011

В Java 6 есть ошибка, связанная с этим.

Этот код будет выдавать различные ошибки, такие как "не удается найти символ..."

assertThat(achievements, hasItem(isA(TestAchievement.class)));

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

Matcher<Iterable<? super TestAchievement>> matcher = hasItem(isA(TestAchievement.class));
assertThat(achievements, matcher);

Интересно, что если вы используете instanceOf() вместо isA(), вы снова столкнетесь с проблемой. (хотя, если вы проигнорируете предупреждения, это все равно может сработать для вас.) Расширение предыдущего исправления, которое вы можете использовать:

Matcher<TestAchievement> itemMatcher = Matchers.instanceOf(TestAchievement.class);
Matcher<Iterable<? super TestAchievement>> matcher = hasItem(itemMatcher);
assertThat(achievements, matcher);
person Mike Rylander    schedule 23.12.2013
comment
Я обычно добавляю комментарий // work around for Java 6 Bug: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7034548 всякий раз, когда это происходит. - person Mike Rylander; 24.12.2013

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

List<Object> listOfThings = (List) someService.findThings(); // your business logic here
Object[] arrayOfThings  = listOfThings.toArray(new Object[listOfThings.size()]);

assertThat(arrayOfThings, hasItemInArray(instanceOf(SpecialThing.class)));

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

person joerx    schedule 14.12.2012
comment
Если вы хотите избежать использования примитивных массивов, см. этот ответ. (Однако у вас все еще будет одна дополнительная строка.) - person Mike Rylander; 24.12.2013

Я некоторое время возился с этим, и кажется, что единственный способ, который я знаю, - это преобразовать List<Achievement> в List<Object>. Проблема в том, что CoreMatchers.instanceOf() возвращает Matcher<Object>.

С этой модификацией я могу заставить это работать: -

List<Object> achievements = new ArrayList<Object>();
achievements.add(new Achievement());
achievements.add(new TestAchievement());
assertThat(achievements, hasItem(instanceOf(TestAchievement.class)));
person limc    schedule 13.02.2011

На самом деле это не работает для немного более сложного Matcher, даже с использованием последней версии.

assertThat(result.getAnswers(),
            Matchers.hasItem(Matchers.hasProperty("content")));

Это не сработает, вы получите:

Метод assertThat(T, Matcher) в типе Assert неприменим для аргументов (Set, Matcher>)

Вы можете решить это, преобразовав его в массив:

assertThat(result.getAnswers().toArray(), hasItemInArray(Matchers.hasProperty("content", equalTo("<h4>new comment</h4>"))));
person Ark Xu    schedule 15.04.2013

Из http://code.google.com/p/hamcrest/source/browse/trunk/hamcrest-java/hamcrest-core/src/main/java/org/hamcrest/MatcherAssert.java подпись

assertThat(T actual, Matcher<? super T> matcher)

так что проблема в том, что ваш сопоставитель - это Matcher<TestAchievement>, а не сопоставитель, который работает для любого экземпляра суперкласса или интерфейса достижения.

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

@SuppressWarnings("unchecked")
Matcher/*no_param*/ isATestAchievement = instanceOf(TestAchievement.class);
assertThat(..., isATestAchievement);
person Mike Samuel    schedule 13.02.2011
comment
Это хороший пример. У меня работает, но только на hamcrest 1.1. Обновление до 1.2 или 1.3.0RC0 выдаст мне ошибку. - person Jesper Rønn-Jensen; 17.03.2011
comment
Ошибка (для версии 1.2) stacktrace: java.lang.NoSuchMethodError: org.hamcrest.Matcher.describeMismatch(Ljava/lang/Object;Lorg/hamcrest/Description;)V at org.hamcrest.core.IsCollectionContaining.matchesSafely(IsCollectionContaining.java :31) в org.hamcrest.core.IsCollectionContaining.matchesSafely(IsCollectionContaining.java:14) в org.hamcrest.TypeSafeDiagnosingMatcher.matches(TypeSafeDiagnosingMatcher.java:54) в org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:12) на org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:8) - person Jesper Rønn-Jensen; 17.03.2011
comment
@JesperRønn-Jensen См. этот ответ. Это работает с hamcrest 1.1 и 1.3. - person Mike Rylander; 24.12.2013

person    schedule
comment
Эта строка не компилируется. Вот сообщение об ошибке: The method instanceOf(Class<?>) of type IsInstanceOf is not generic; it cannot be parameterized with arguments <Achievement> - person limc; 13.02.2011
comment
@limc Это общий код в стволе: code.google.com/p/hamcrest/source/browse/trunk/hamcrest-java/ - person NamshubWriter; 13.02.2011