This is a good example of how Hamcrest can make testing with collections easier. For example, to test the findByName() method, you should be able to something like this:
This Hamcrest assert checks that the list contains at least one Stakeholder object whose name is "Health Associates". This is clearly much nicer than having to iterate through the result list and test each Stakeholder object individually.
Unfortunatly, this doesn't work: you get a compilation error along the following lines:
The method assertThat(T, Matcher) in the type MatcherAssert is not applicable for the arguments (List<Stakeholder>, Matcher>)
Indeed, Hamcrest seems to be having trouble with the idea that a List of Stakeholders is also a List of Objects.
So can't we just cast the result (a List<Stakeholder> object) to a List<Object>? The short answer is no. For type-safety reasons that are well-documented elsewhere, you can't cast a List<Stakeholder> to a List<Object>. If you could do this, you could add objects that weren't Stakeholders to the list. However, you can find a work-around fairly easily. But this is where the details get rather interesting. For example, the following seems to compile in Eclipse, but nowhere else:
List stakeholders = stakeholderManager.findByName("Health");
assertThat(stakeholders, hasItem(hasProperty("name",is("Health Associates"))));
Outside Eclipse, this will fail with an error along the following lines:
StakeholderManagerTest.java:[62,8] cannot find symbol
symbol : method assertThat(java.util.List,org.hamcrest.Matcher>)
My friend Eduard Letifov pointed out the following solution, which will work both within Eclipse and using a normal JDK:
List stakeholders = stakeholderManager.findByName("Health");
assertThat((List<Object>) stakeholders, hasItem(hasProperty("name",is("Health Associates"))));
That's right, there are two casts here: one from List<Stakeholder> to List, and a second from List to List<Object>. There's sure to be a more elegant way, but it probably involves modifying the signature of the Hamcrest methods. So this will do for now.
I generally pull out my own static factory methods for matchers in cases like this.
There is a Java language proposal that would make your code work but for now you'll have to choose one of these options.
We've had a few issues trying to suite everybody's needs with regards to generics. I'm working on getting a 1.2 release out which should be more flexible.
Posted by: neildunn on April 23, 2008 at 11:31 PM
Sorry java.net sucked up my angle braces. The code sample should be: