Issue
I am trying to allow my test classes to access the main classes (in a standard gradle setup). It was working fine until I put my main classes in a module (for JavaFX), at which point all tests stopped working. The main code runs fine.
If I understand correctly, according to this gradle documentation, doing nothing should run the tests normally, but I get an error:
org.gradle.api.internal.tasks.testing.TestSuiteExecutionException: Could not complete execution for Gradle Test Executor 1.
...
Caused by: java.lang.IllegalAccessError: class org.junit.platform.launcher.core.LauncherFactory (in unnamed module @0x50650eec) cannot access class org.junit.platform.commons.util.Preconditions (in module org.junit.platform.commons) because module org.junit.platform.commons does not export org.junit.platform.commons.util to unnamed module @0x50650eec
This happens if I use the intellij configuration, or run ./gradlew test
.
So I attempted to fix the issue by patching the module-info, but then I get hundreds of errors like this one:
error: cannot find symbol
import snake.Snake
^
symbol: class Snake
location: package snake
Which IntelliJ explains with Package 'snake' is declared in module 'snakegame', which does not export it to module 'snakegame'
. I'm guessing that it's referring to the original module-info.java which is defined in src/main/java, and the secondary module-info.java in src/test/java.
In the Gradle documentation it had a code snippet for adding the patch argument yourself in the build.gradle, however this just results in this error:
> java.lang.IllegalArgumentException: error: --patch-module specified more than once for module snakegame
The command which was actually executed looks like this:
compiler args for task compileTestJava: [--patch-module, snakegame=/project/path/snake/build/classes/java/main, --module-path, ... , --add-modules, org.junit.jupiter.api, --add-reads, snakegame=org.junit.jupiter.api, --patch-module, snakegame=/project/path/snake/src/test/java]
So it's patching two different modules, which I don't understand. It doesn't really matter to me how, I just need the classes to be runnable and have access to the main classes.
UPDATE:
So I recreated the project to try to create a minimal reproducible example and added in elements one at a time, and the problem didn't show up until I added in the gradle JavaFX plugin, at which point it stopped working.
So I started with the default structure, simply created a package called example
with an Example.class
, and created the same package in test, with a test class Example_Test.class
with one test that creates an Example object. I then added an empty module-info in main. Original build.gradle:
plugins {
id 'java'
}
// default stuff
So at this point, everything is working fine. Then I change this to:
plugins {
id 'java'
id 'org.openjfx.javafxplugin' version '0.0.9'
}
And everything stops working
Solution
My preferred solution would be to use a test module-info.java or module-info.test, but I was not able to get this to work. I ended up simply ignoring modules for tests, which is a terrible workaround, but works for the moment. To ignore modules during testing, add this to the build.gradle:
plugins {
id 'java'
id 'org.openjfx.javafxplugin' version '0.0.9'
// other plugins
}
// other stuff
test {
useJUnitPlatform()
moduleOptions {
runOnClasspath = true
}
}
Set moduleOptions { runOnClasspath = true }
in test
Useful links:
- https://stackoverflow.com/a/58854685/12393574
- https://github.com/junit-team/junit5/issues/2111#issuecomment-557925312
- https://sormuras.github.io/blog/2018-09-11-testing-in-the-modular-world.html
- https://stackoverflow.com/a/58990250/12393574
- The JavaFX plugin adds the gradle-modules-plugin
Answered By - jeffrey.d.m