Unit tests inside Eclipse succeed, unit tests in Maven fail. WTF?

Our new project makes use of Maven as build management tool. Eclipse (STS edition) is used for the development process. A part of the project consists of a transformation process which converts XML files to Java POJOs. Because of the given XML structure we used JAXB in combination with EclipseLink MOXy for this.

After a few weeks of initial development, mainly architectural decisions I prepared our TeamCity instance. The first TeamCity build failed because some of the unit tests throw unexpected errors. I must admit that until this time I had only executed the unit tests through Eclipse and every test case had passed without any problem. My local command line Maven builds were triggered with -DskipTests=true and succeeded too.

The failed build in TeamCity occured through the following JAXB error:

com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
org.springframework.integration.Message is an interface, and JAXB can't handle interfaces.
	this problem is related to the following location:
		at org.springframework.integration.Message
		at public org.springframework.integration.Message ...

I repeated the test suite on my local machine (mvn test) and the first time it ran it succeeded. Eclipse passed the unit tests, too. At first I suspected different Java/JDK versions on my local machine and the build server, but the versions were the same. So I started with a fresh mvn clean test on my machine and the build failed, too. WTF? Now running the compiled unit test and the source code in Eclipse although resulted in the error above. Re-compiling the code with Eclipse fixed the errors. Eclipse uses Eclipse Compiler for Java (ECJ) during compilation and not javac of the JDK. Could it be a compiler bug? The byte code of both .class files (Maven compiled vs. Eclipse compiled) were more or less the same so this was not the answer.

During debugging the Maven compiled artifacts I noticed that the MOXy compiler was not hit, instead the default implementation was used. Could it be that the jaxb.properties file was not copied to the class path? jaxb.properties is read by JAXB for initializing/overwriting the default XML context factory. And indeed, the jaxb.properties was missing. ECJ copied the .properties file to the target directory but Maven ignored the file.

What did I learned from that?

  1. Fail early – Set up the build infrastructure on the first day of your project and don’t wait until a first prototype is available.
  2. Fail everywhere – Running the tests only in one environment (Eclipse) does not mean that it succeeds in other environments (pure Maven).
  3. Don’t skip tests – Waiting for a local build to succeed sucks. Skipping the unit tests makes it better, but a failed build in another environment (see 2.) although sucks.