NoClassDefFoundError com_atlassian_clover/CoverageRecorder
症状
During execution of tests or application a following message appears:
FATAL ERROR: Clover could not be initialised. Are you sure you have Clover in the runtime classpath?
...
(class java.lang.NoClassDefFoundError:com_atlassian_clover/CoverageRecorder)
or
(class java.lang.NoClassDefFoundError:com_atlassian_clover/CloverVersionInfo)
or
(class java.lang.NoClassDefFoundError:com_atlassian_clover/CloverProfile)
or there is a stack trace related with class initialization (Spring, Tomcat container, class loaders ...)
<stack trace describing that initialization of some class has failed or that some field is null followed by>
...
Caused by: java.lang.NoClassDefFoundError: Lcom_atlassian_clover/TestNameSniffer <or other clover class>
原因
In 99% of cases this is caused by a fact that Clover's JAR (clover.jar in case of Ant, com.atlassian.clover:clover artifact in case of Maven) is missing in runtime. Please keep in mind that it's not enough to have clover.jar during compilation - classes instrumented by Clover needs Clover's core classes from clover.jar during application (or test) execution.
This kind of error may appear in various contexts, typical cases are:
Ant JUnit tests
- when you run unit tests in a forked JVM (<junit> Ant task), without clover.jar declared in <classpath/>
Running tests in a container instantiated on the fly
- occurs usually in Ant / Maven / Bamboo / Jenkins / Hudson builds
- when you instantiate container of the fly (e.g. using maven-cargo-plugin)
Running tests of an application deployed on a remote machine
- when you deploy EAR/WAR to application server but without clover.jar bundled in the archive or installed in /lib
Bamboo
- occurs usually when "automatic Clover integration" is enabled and you have tests running in separate JVM (for instance in-container tests or tests accessing business logic on an application server)
- may occur if you have a multi-module Maven build with inter-module dependencies and when the automatic Clover integration is used
- may happen for "automatic Clover integration" with Ant, Maven or Grails
Maven
- when you have Maven build with some extra plug-ins, run tests in-container etc
Eclipse
- when you choose 'Run as ...' instead of 'Run with Clover as ..' from main menu
- in RCP or OSGI applications
IDEA
- when you uninstalled Clover plug-in
ソリューション
Ant JUnit tests
Add clover.jar to runtime classpath for forked junit tests, for instance:
<junit fork="yes">
<classpath>
<pathelement location="/path/to/clover.jar"/>
<pathelement path="/path/to/other/application.jars"/>
<classpath>
</junit>
Tests executed in container / on a remote machine
1) In case you use standalone server, the easiest way is to copy the clover.jar into the server's /lib directory. Thanks to this you won't need to deploy it together with the application (but at the cost that all applications deployed will have to be instrumented using the same Clover version; and you'll have to remember about upgrading clover.jar in server's /lib when necessary).
Alternatively, you can bundle clover.jar into your application's EAR / WAR.
2) In case you instantiate container on the fly, make sure that Clover JAR dependency is declared for runtime. Example for maven-cargo-plugin can be found here:
https://bitbucket.org/atlassian/maven-clover2-plugin folder /src/it/webapp
...
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<configuration>
<container>
<dependencies>
<!-- We need clover.jar to be present in container classpath -->
<dependency>
<groupId>com.atlassian.clover</groupId> <!-- com.cenqua.clover for Clover 3.x -->
<artifactId>clover</artifactId>
</dependency>
</dependencies>
</container>
...
</configuration>
</plugin>
Bamboo
1) If you use Automatic Clover integration and have code running in separate JVM then you have to add dependency to the com.atlassian.clover:clover artifact (com.cenqua.clover:clover for Clover 3.x). See 'Ant JUnit tests', 'Tests executed in container' and 'Maven' chapters on this page.
2) If you have a multi-module Maven project with dependencies between modules and use manual Clover integration, it can happen that an instrumented version of the dependent artifact will be fetched from a repository (or local ~/.m2 repository cache) for a non-Clover build. Be careful not to use "mvn deploy" (or "mvn install") together with clover:setup (Clover 4.1 or newer) / clover2:setup (before Clover 4.1) goal, otherwise your repository will contain instrumented artifacts. We recommend the following:
- use the "clover:setup" goal with a build till the "verify" phase (the latest) or
- use the "clover:instrument" goal (it forks a parallel build life cycle so that all artifacts produced have a '-clover' suffix).
3) If you have a multi-module Maven project with dependencies between modules and use Automatic Clover integration, it can happen that an instrumented JAR of the dependent artifact will be taken for test execution in a build phase where Clover was not enabled yet. See BAM-13208 for more details (this has been fixed in Bamboo 5.9). We recommend the following:
- 自動 Clover 統合が有効になっている別のジョブを作成します。
- create a Maven task in this job, which will do nothing (call "clean" goal, for instance)
- Bamboo will automatically add Clover-related goals ("clover:setup verify clover:aggregate clover:clover" for Clover 4.1 or newer, "clover2:setup verify clover2:aggregate clover2:clover" before Clover 4.1)
Maven
Some plug-in may need to have Clover dependency declared explicitly (e.g. for packaging artifacts, starting a container ...).
Usually, adding a following dependency to a configuration section of the specific plug-in solves the problem - exact syntax depends on the plug-in:
<!-- usually under the <configuration> / <dependencies> section - depends on a plug-in -->
<dependency>
<groupId>com.atlassian.clover</groupId> <!-- com.cenqua.clover for Clover 3.x -->
<artifactId>clover</artifactId>
</dependency>
参照先:
- Using Clover with JAXB plugin
- Using Clover with Maven Tycho Plugin
- Using Clover with Maven Cargo Plugin
Eclipse
When you use "Run with Clover as..." from main menu, Clover-for-Eclipse enhances the -Xbootclasspath by adding a path to com.atlassian.clover.eclipse.runtime-<version>.jar from Eclipse installation directory. However, because of the fact that it's not always possible to use "Run with Clover as..." option (for instance when you'd like to debug or profile application), you have to modify your runtime configuration and add -Xbootclasspath manually. Example:
IDEA
In case when you uninstall Clover plug-in, you have to rebuild the whole project to ensure that no instrumented classes are left.
参考