Question

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?

Was it helpful?

Solution

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)));

OTHER TIPS

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);
assertThat(achievements, hasItem(
    IsInstanceOf.<Achievement>instanceOf(TestAchievement.class)));

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.

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)));

Actuall it does not work for a little bit more complex Matcher, even using latest release.

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

It will not work, you will get a:

The method assertThat(T, Matcher) in the type Assert is not applicable for the arguments (Set, Matcher>)

You can solve it by converting it to an array :

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

From http://code.google.com/p/hamcrest/source/browse/trunk/hamcrest-java/hamcrest-core/src/main/java/org/hamcrest/MatcherAssert.java the signature is

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

so the problem is that your matcher is a Matcher<TestAchievement>, not a matcher that works for any instance of a super-class or interface of achievement.

It looks like the instanceOf matcher just has a buggy type bound. You can work around that bug by doing something like

@SuppressWarnings("unchecked")
Matcher/*no_param*/ isATestAchievement = instanceOf(TestAchievement.class);
assertThat(..., isATestAchievement);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top