I have an "executable" Java 9 module (meaning it won't expose any packages, it just contains a main function) which I need to test.
I am using Gradle's java-library and org.gradle.java.experimental-jigsaw plugins.
I have some package-private methods I need to test, and when I run in IntelliJ the tests work, but when running with Gradle, I get many errors like this:
abc.MyClassTest > myTestMethod FAILED
java.lang.IllegalAccessException
In the Gradle report, I see the root of the error:
class org.junit.runners.BlockJUnit4ClassRunner (in module junit)
cannot access class abc.MyClassTest (in module com.my.mod)
because module com.my.mod does not export abc to module junit
If I add this to my module-info.java file, it works with a warning:
exports abc to junit; // I don't really want to export this
Warning (when compiling):
warning: [module] module not found: junit
This looks pretty horrible even without the warning, in my opinion.
My question: how to "open" this package for tests only to avoid warnings and errors?
解决方案
As the Gradle Plugin is still experimental (6 months after the release of Java 9), it seems it still has some bugs and missing features.
But here's how to work around the issue while the Gradle devs don't improve the situation.
Add this to your build file:
test {
doFirst {
jvmArgs += [
'--add-exports', "module/package=junit",
]
}
}
Where module/package is the name of the module and package you need to make visible to JUnit.
This is basically equivalent to the exports package to junit clause in module-info.java, but without having the clause make into the compiled jar!
This option is not documented in javac -help, but you can at least find it mentioned in the Oracle JDK Docs and, more thoroughly, in JEP-261... see the Breaking encapsulation section.