Search code examples
javaclassloaderjunit4javaagents

Using javaagent with Junit is causing ClassNotFoundException in Class.forName


java -classpath requiredclasspath org.junit.runner.JUnitCore some.package.HelloWorldTest

results in:

JUnit version 4.8.1
.

Time: 0.005

OK (1 test)

But:

java -javaagent:agent.jar -classpath requiredclasspath org.junit.runner.JUnitCore some.package.HelloWorldTest    

results in:

JUnit version 4.8.1
Could not find class: some.package.HelloWorldTest

Time: 0.001

OK (0 tests)

The core issue seems to be that:

Class.forName("some.package.HelloWorldTest") (runMain method, line 89, JunitCore)

throws a ClassNotFoundException as follows:

java.lang.ClassNotFoundException: some/package/HelloWorldTest
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:169)
at org.junit.runner.JUnitCore.runMain(JUnitCore.java:89)
at org.junit.runner.JUnitCore.runMainAndExit(JUnitCore.java:53)
at org.junit.runner.JUnitCore.main(JUnitCore.java:45)

I dont know why it cannot find the class. Note that the instrumentation agent is loaded successfully and does not throw any exceptions.


Solution

  • Turns out I had the junit jar in the boot classpath specified for the javaagent as well as the user classpath specified through -classpath i.e. the manifest for agent.jar had the following entry:

    Boot-Class-Path: ...junit.jar...
    

    and the -classpath argument to the java command had the following:

    -classpath ...junit.jar...
    

    I was able to fix the problem by removing junit.jar from the manifest boot classpath entry. Here is a short explanation of the problem:

    Since junit.jar was included in the boot classpath, org.junit.runner.JUnitCore was first loaded using the boot classloader. So when Class.forName was invoked within JunitCore, it tried to find the class using the boot classloader which could not find the class since it was not part of the boot classpath.