Java Hamcrest : Collection contains item of type

17,132

Solution 1

Thanks for all the help.

The posts here suggested it was a defect with Hamcrest, so I headed over to the hacmrest site to register a bug, whien I discovered that the mvn / ivy dependency declaration I was using was out-of-date, giving me an old version of Hamcrest.

This bug exists with 1.1, which is the latest if declared using

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

However, the correct depedency declaration is:

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

Updating to this solved the issue. The syntax used in my test is:

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

Solution 2

There is a bug in Java 6 that relates to this.

This code will throw various errors such as "cannot find symbol..."

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

The work around for this is to declare the matcher as a variable and then reference that variable. It is important to note that the type of the variable, specifically the generics section, is very important for this to work.

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

Interestingly if you use instanceOf() instead of isA() you once again run into issue. (although if you ignore the warnings this might just work for you anyway.) Expanding on the previous fix you can use:

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

Solution 3

assertThat(achievements, hasItem(
    IsInstanceOf.<Achievement>instanceOf(TestAchievement.class)));

Solution 4

I've been battling with this for a while, none of the approaches here really had the expected result. Out of pure despair I tried converting to an array to see if that made a difference:

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

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

And it did make a difference. Now my test works flawlessly. The one line of copy-to-array seems to be a reasonable trade-off to save a lot of hassle.

Solution 5

I have been futzing around with this for awhile, and it seems like the only way I know is to convert List<Achievement> to List<Object>. The problem is CoreMatchers.instanceOf() returns Matcher<Object>.

With that modification, I'm able to get this to work:-

List<Object> achievements = new ArrayList<Object>();
achievements.add(new Achievement());
achievements.add(new TestAchievement());
assertThat(achievements, hasItem(instanceOf(TestAchievement.class)));
Share:
17,132
Marty Pitt
Author by

Marty Pitt

Updated on June 06, 2022

Comments

  • Marty Pitt
    Marty Pitt almost 2 years

    I'd like to assert that List<Achievement> contains a member of type TestAchievement.

    Here's my assertion:

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

    This doesn't compile, reporting the error:

    The method assertThat(T, Matcher) in the type Assert is not applicable for the arguments (List, Matcher<Iterable<TestAchievement>>)

    What's the correct syntax for this type of assertion using Hamcrest?

  • limc
    limc about 13 years
    That line doesn't compile. Here's the error message: The method instanceOf(Class<?>) of type IsInstanceOf is not generic; it cannot be parameterized with arguments <Achievement>
  • tchrist
    tchrist about 13 years
    I spent nearly a week of headbanging once on this very same problem of a buggy declaration in the hamcrest library code before I finally stumbled on the fixed updated version. Just nuts! Things should not be this complicated.
  • NamshubWriter
    NamshubWriter about 13 years
    @limc It's generic in the code at the trunk: code.google.com/p/hamcrest/source/browse/trunk/hamcrest-java‌​/…
  • Jesper Rønn-Jensen
    Jesper Rønn-Jensen about 13 years
    This is a good example. Works for me but only on hamcrest 1.1. Upgrading to 1.2 or 1.3.0RC0 will give me n error.
  • Jesper Rønn-Jensen
    Jesper Rønn-Jensen about 13 years
    The error (for 1.2) stacktrace: java.lang.NoSuchMethodError: org.hamcrest.Matcher.describeMismatch(Ljava/lang/Object;Lorg‌​/hamcrest/Descriptio‌​n;)V at org.hamcrest.core.IsCollectionContaining.matchesSafely(IsCol‌​lectionContaining.ja‌​va:31) at org.hamcrest.core.IsCollectionContaining.matchesSafely(IsCol‌​lectionContaining.ja‌​va:14) at org.hamcrest.TypeSafeDiagnosingMatcher.matches(TypeSafeDiagn‌​osingMatcher.java:54‌​) at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:12) at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:8)
  • Mike Rylander
    Mike Rylander over 10 years
    I typically add the comment // work around for Java 6 Bug: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7034548 whenever this comes up.
  • Mike Rylander
    Mike Rylander over 10 years
    If you want to avoid using primitive arrays see this answer. (You will still have the one extra line though.)
  • Mike Rylander
    Mike Rylander over 10 years
    @JesperRønn-Jensen See this answer. This works with hamcrest 1.1 and 1.3.