Monday, October 14, 2013

More Hamcrest Hassles

The Hamcrest library is very useful. So useful that other useful libraries, like JUnit, include pieces of it. And then JUnit is so useful that Eclipse includes its own copy.

Not surprisingly, having multiple copies, of different versions, of different subsets, with some signed and some not, results in numerous problems. For accounts of my own experiences see: Upgrading to Eclipse Kepler 4.3, Eclipse Hamcrest Runaround, and I Give Up. Searching the web will find lots of other people with similar problems.

Once again, I had thought I had solved this by not using Eclipse's copy of JUnit. Everything has appeared to be working fine for months.

Until I was adding a test today. In good TDD style, I started by adding the test before making the change. It failed, as expected, but not with the error message I expected. I got:

java.lang.NoSuchMethodError: org.hamcrest.Matcher.describeMismatch

I thought maybe it was because I was using org.junit.Assert.assertThat instead of org.hamcrest.MatcherAssert.assertThat - but switching it didn't fix anything.

I also noticed that Eclipse was marking org.hamcrest.CoreMatchers.is as deprecated. Maybe it should be org.hamcrest.Matchers.is? Nope, still deprecated. I eventually found a comment on Stack Overflow that there are three overloads of "is" and it's only the class one that is deprecated, not the one I'm using. So I guess I just live with that warning :-(

Another comment on Stack Overflow mentioned that Mockito also included it's own version of Hamcrest. Hmmm... I don't think I was aware of that before.

One of the suggested solutions to this problem is to rearrange the order of the jar files on the class path. I had tried that previously without any success. But I was only moving JUnit and Hamcrest, since I wasn't aware that Mockito was also involved.

I find the Eclipse project properties Java Build Path a little confusing. There's a Libraries tab that lists all the jars alphabetically and you can't change the order. And then there's an Order and Export tab where you can change the order. I'm not sure why two tabs are needed. There's also a Referenced Libraries in the Package Explorer that does show the actual order, but doesn't let you change it.

I moved Mockito down in the list so it was below Hamcrest (JUnit was already below) and sure enough, that solved the problem.

Except now I had a different error in another test. That one turned out to be because I was using "is" with a class. Maybe it's deprecated in one of the versions/copies of Hamcrest but removed in the version of Hamcrest I'm explicitly including? Luckily this was simple to fix by just changing it to instanceOf.

It looks like you can download separate jars for Mockito which would let you leave out it's copy of Hamcrest. Except that it appears to be using a different version of Hamcrest (1.1) from the one I'm using (1.3). I have no idea if that would cause problems, but since it's currently not broken, I don't think I'll try to fix it!

Probably someone out there will tell me that I should be using Maven to manage dependencies, and maybe I should. But I'm not so sure that would eliminate these problems. I see several comments on the web about the same issues when using Maven.

No comments: