Closed m-kuklinski closed 6 years ago
What I need to know is: how to reproduce the problem? Also, JMockit 1.28 is very old; does it still occur with the current version (1.41)?
It also happens on trunk from the git repository, which was what I developed my patch off of.
To reproduce it? Windows 10, JDK8, IntelliJ... and try to debug a JUnit5 unit test. I'd have to set up a minimal case for you otherwise. I'll work on that in a bit.
It's working fine for me (specifically, with https://github.com/jmockit/jmockit1/blob/master/samples/java8testing/test/java8testing/JUnit5Test.java, and putting a breakpoint at line 14 of https://github.com/jmockit/jmockit1/blob/master/samples/java8testing/src/java8testing/BusinessService.java. Using IntelliJ 2018.1 and JDK 1.8.0_144 on Windows 7 (but I doubt that IntelliJ, Windows, or even the JDK has anything to do with it).
I am able to reproduce it with your JUnit5Test if I change the debugger to use classpath files instead of the default 'none' (which we cannot use on Windows due to our class paths being insanely long).
I'd suggest adding unit tests for the differing 'Shorten command line' options.
JUnit5Test$InnerTest.innerTest
none
: works
JAR manifest
: works
classpath file
: fails due to not initializing JMockit (due to no agent being loaded).
The output for classpath file in that situation looks like this:
"C:\Program Files\Java\jdk1.8.0_181\bin\java.exe" -agentlib:jdwp=transport=dt_shmem,address=javadebug,suspend=y,server=n -ea -javaagent:C:\Users\kuklinsk\.m2\repository/org/jmockit/jmockit/1.42/jmockit-1.42.jar -Didea.test.cyclic.buffer.size=1048576 -javaagent:C:\Users\kuklinsk\.IdeaIC2018.2\system\captureAgent\debugger-agent.jar=file:/C:/Users/kuklinsk/AppData/Local/Temp/capture.props -Dfile.encoding=UTF-8 -classpath "C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2018.1.6\lib\idea_rt.jar" com.intellij.rt.execution.CommandLineWrapper C:\Users\kuklinsk\AppData\Local\Temp\idea_classpath1632644453 com.intellij.rt.execution.junit.JUnitStarter -ideVersion5 -junit5 java8testing.JUnit5Test$InnerTest,innerTest
Connected to the target VM, address: 'javadebug', transport: 'shared memory'
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.CommandLineWrapper.main(CommandLineWrapper.java:67)
Caused by: java.util.ServiceConfigurationError: org.junit.platform.engine.TestEngine: Provider mockit.integration.junit5.JMockitTestEngine could not be instantiated
at java.util.ServiceLoader.fail(ServiceLoader.java:232)
at java.util.ServiceLoader.access$100(ServiceLoader.java:185)
at java.util.ServiceLoader$LazyIterator.nextService(ServiceLoader.java:384)
at java.util.ServiceLoader$LazyIterator.next(ServiceLoader.java:404)
at java.util.ServiceLoader$1.next(ServiceLoader.java:480)
at org.junit.platform.launcher.core.DefaultLauncher.validateUniqueIds(DefaultLauncher.java:63)
at org.junit.platform.launcher.core.DefaultLauncher.<init>(DefaultLauncher.java:58)
at org.junit.platform.launcher.core.LauncherFactory.create(LauncherFactory.java:59)
at com.intellij.junit5.JUnit5IdeaTestRunner.createListeners(JUnit5IdeaTestRunner.java:42)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:45)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
... 5 more
Caused by: java.lang.IllegalStateException: JMockit didn't get initialized; please check the -javaagent JVM initialization parameter was used
at mockit.internal.startup.Startup.verifyInitialization(Startup.java:91)
at mockit.integration.junit5.JMockitTestEngine.<init>(JMockitTestEngine.java:26)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at java.lang.Class.newInstance(Class.java:442)
at java.util.ServiceLoader$LazyIterator.nextService(ServiceLoader.java:380)
... 14 more
Disconnected from the target VM, address: 'javadebug', transport: 'shared memory'
Process finished with exit code 1
Empty test suite.
The output for using a JAR manifest looks like:
"C:\Program Files\Java\jdk1.8.0_181\bin\java.exe" -agentlib:jdwp=transport=dt_shmem,address=javadebug,suspend=y,server=n -ea -javaagent:C:\Users\kuklinsk\.m2\repository/org/jmockit/jmockit/1.42/jmockit-1.42.jar -Didea.test.cyclic.buffer.size=1048576 -javaagent:C:\Users\kuklinsk\.IdeaIC2018.2\system\captureAgent\debugger-agent.jar=file:/C:/Users/kuklinsk/AppData/Local/Temp/capture.props -Dfile.encoding=UTF-8 -classpath C:\Users\kuklinsk\AppData\Local\Temp\classpath1088636867.jar com.intellij.rt.execution.junit.JUnitStarter -ideVersion5 -junit5 java8testing.JUnit5Test$InnerTest,innerTest
Connected to the target VM, address: 'javadebug', transport: 'shared memory'
Disconnected from the target VM, address: 'javadebug', transport: 'shared memory'
Process finished with exit code 0
Yeah, I could reproduce it now. It only happens with one of four different options for the "Shorten command line" field in IntelliJ's run configuration, the "classpath file" one. And it occurs with any test runner (JUnit 4 or 5, and I imagine TestNG as well). Nothing to do with the debugger, or the JDK version, or the OS.
The problem occurs because IDEA launches the test run in two steps, first using the regular app classloader, with jmockit.jar present, but junit.jar absent. And then it starts actually running the tests under a custom classloader, having the full classpath. So, in the first step, JMockit cannot activate its JUnit integration since JUnit is not in the runtime classpath; and in the second step, it can't find the Instrumentation
object loaded in the first step, since now everything is loaded on a different classloader (therefore, the static field value got lost).
However, I think the simplest solution is to not use the "classpath file" option. The other three options should work (they work for me on a large project where the runtime classpath is over 15000 characters long, on Windows 10).
I'm facing the same issue with the version v1.44
. So I downgraded to v1.41
and it's fully working now...
My config : JUnit5 5.10, IntelliJ 2018.2, JDK 1.8.0.131
The same problem with detached classloaders exist when using jmockit with arquillian based tests. The classloader of the tests is detached from the systemclassloader. Only the class mockit.internal.startup.Startup of the Systemclassloader was instrumented (instrumentation is not null) . All other AppClassloaders have no instrumentation.
Version: JMockit 1.28, JUnit5 5.20, IntelliJ 2018.2, tested JDK 1.8.0.181, 10.0.2, and 11.
When attempting to debug a unit test of a Maven project in IntelliJ on Windows, I get a NullPointerException in createSyntheticFieldsInJREClassToHoldClassLoadingBridges. The call stack is as follows:
java.lang.NullPointerException at mockit.internal.startup.ClassLoadingBridgeFields.createSyntheticFieldsInJREClassToHoldClassLoadingBridges(ClassLoadingBridgeFields.java:27) at mockit.internal.startup.Startup.initializeIfPossible(Startup.java:126) at mockit.integration.junit5.JMockitTestEngine.<init>(JMockitTestEngine.java:26) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at java.lang.Class.newInstance(Class.java:442) at java.util.ServiceLoader$LazyIterator.nextService(ServiceLoader.java:380) at java.util.ServiceLoader$LazyIterator.next(ServiceLoader.java:404) at java.util.ServiceLoader$1.next(ServiceLoader.java:480) at org.junit.platform.launcher.core.DefaultLauncher.validateUniqueIds(DefaultLauncher.java:65) at org.junit.platform.launcher.core.DefaultLauncher.<init>(DefaultLauncher.java:60) at org.junit.platform.launcher.core.LauncherFactory.create(LauncherFactory.java:57) at com.intellij.junit5.JUnit5IdeaTestRunner.createListeners(JUnit5IdeaTestRunner.java:42) at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:45) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at com.intellij.rt.execution.CommandLineWrapper.main(CommandLineWrapper.java:67)
Upon further investigation, this is happening as IntelliJ does not pass any runtime information, which causes JMockit to execute the agent, which updates the variable instrumentation, and then continues execution with it upon the return of the agent. On my system, the splitting of the VM during this process appears to create a detached ClassLoader, and thus creates a separate class altogether, complete with its own copy of the static instrumentation variable. I confirmed this via debugging. Thus, when the instrumentation variable is updated, it is not updated in the original context, which is under a separate class altogether (although with the exact same prototype/name, but a different ID in the VM and a different memory space).
This does not happen:
I have forked the project on github, and patched it in a way that uses reflection to update all potential copies of instrumentation to work around this issue, which appears to work on my system.