Hello everyone,
I'm dealing with the following issue: I have got a JavaFX JDK 11 project with two modules: main and test. Main holds all the source code and the source code resources. And test holds all the JUnit tests and the related resources. Everything used to work fine before when I ran "gradlew test" with the useJUnitPlatform() command. But as soon as I added a module-info to my main module things started going downhill.
For a start, I would like to point out that adding this module-info.java file is a required part of building my application, so the solution of "just remove it!" would work to get the tests back working, but sadly isn't possible.
Following days of research I am not able to solve the issue myself and I have been stuck on the same set of errors for days:
C:...\src\test\java\module-info.java:1: error: module name FP.EDM.test does not match expected name FP.EDM.main
open module FP.EDM.test {
^
C:...\src\test\java\module-info.java:3: error: cyclic dependence involving FP.EDM.main
requires FP.EDM.main;
^
error: cannot access module-info
cannot resolve modules
warning: module name in --add-reads option not found: FP.EDM.main
3 errors
1 warning
I have got the following module-info.java file in my main module:
open module FP.EDM.main {
//Exposes the main class for distribution
exports edm;
//Exposes all tested classes to the test module
exports edm.utilities;
exports edm.model.enumerations;
exports edm.writers;
exports edm.model;
exports edm.handlers;
exports edm.readers.importFileReaders;
exports edm.model.interfaces;
//JavaFX requirements
requires javafx.graphics;
requires javafx.controls;
requires javafx.fxml;
//Required for getting desktop metadata
requires java.desktop;
//Reading JSON files
requires json;
//Reading excel files
requires poi;
requires poi.ooxml;
requires xmlbeans;
requires jdk.charsets;
//Ribbon
requires fxribbon;
//Reading CSV files
requires commons.csv;
//Required for doing automatic timestamp calculations
requires org.apache.commons.lang3;
}
And the module-info.java below is part of the test module:
open module FP.EDM.test {
requires org.junit.jupiter.api;
requires FP.EDM.main;
}
The thing of which I believe causes the issue is the fact that useJUnitPlatform uses the main module whenever I print the module above the test command. So I have been looking for a way to set the module to the test module, but have been unable to find such a thing. That's the reason why I believe the issue belongs here on GitHub rather than any other help website.
Please feel free to request additional information, for a start I have also included my build.gradle below.
plugins {
id 'application'
id 'org.openjfx.javafxplugin' version '0.0.8'
id 'org.beryx.jlink' version '2.16.4'
}
version '1.0.0'
sourceCompatibility = 11
repositories {
maven { url "https://dl.bintray.com/dukke/maven" }
maven { url "https://repo.maven.apache.org/maven2/" }
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
testCompile group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.6.0-M1'
testRuntime('org.junit.jupiter:junit-jupiter-engine:5.4.2')
compile group: 'org.apache.commons', name: 'commons-collections4', version: '4.0'
compile 'com.pixelduke:fxribbon:1.2.1'
compile group: 'org.json', name: 'json', version: '20160810'
compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.9'
compile group: 'org.apache.commons', name: 'commons-collections4', version: '4.4'
compile group: 'org.apache.commons', name: 'commons-compress', version: '1.19'
compile group: 'org.apache.commons', name: 'commons-csv', version: '1.7'
compile group: 'org.apache.poi', name: 'poi', version: '4.1.1'
compile group: 'org.apache.poi', name: 'poi-ooxml', version: '4.1.1'
}
jlink {
mergedModule {
requires "java.xml"
requires "javafx.controls"
}
addExtraDependencies("javafx")
launcher {
name = 'gPROMS EDM'
}
}
tasks.jlink.doLast {
copy {
from('src/main/resources')
into("$buildDir/image/bin/src/main/resources")
}
}
test {
println(moduleName)
useJUnit()
}
javafx {
version = "11.0.2"
modules = [ 'javafx.controls', 'javafx.fxml' ]
}
application {
mainClassName = 'FP.EDM.main/edm.Main'
}
Did you give https://github.com/java9-modularity/gradle-modules-plugin a shot? It should take care of most Gradle-related configuration issues out-of-the-box and it offers a bunch of configuration options to tweak the compile and runtime settings.
@siordache's input might be of help here -- if you (@SSchepers) provide a mcve with less dependencies and moving parts involved. Speaking of dependencies:
testCompile group: 'junit', name: 'junit', version: '4.12'
testCompile group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.6.0-M1'
testRuntime('org.junit.jupiter:junit-jupiter-engine:5.4.2')
This is a very strange mixture of components. It should look more like this (test-wise):
@SSchepers My proposed solution is: "just remove it!" 馃槇
But I'm not talking about the module-info.java in your main module. The problem is the one in the src/test/java directory.
When doing whitebox testing, you don't want (and, due to split packages, you cannot build) a separate "test module". Instead, for testing purposes, you need to patch your main module with the classes produced by compiling the code in src/test/java.
You use org.openjfx.javafxplugin, which automatically applies the gradle-modules-plugin. And this plugin patches the main module for you. It also detects the test framework used by your application and configures the necessary compiler flags for it (--add-modules, --add-reads, --add-opens).
As pointed by @sormuras, your build.gradle contains a strange mixture of JUnit 4 and 5. I'm not sure if the gradle-modules-plugin can handle this correctly.
If your tests need to access types from modules not required by your main module, you can pass the necessary additional compiler flags in a module-info.test file (this feature has been contributed by @sormuras). For example, if you use AssertJ in your tests, you need to put this in your module-info.test:
--add-modules
org.assertj.core
--add-reads
FP.EDM.main=org.assertj.core
So, my proposed solution is:
build.gradle and your test code to use only JUnit 5.src/test/java/module-info.javamodule-info.test file in src/test/java, with additional compiler flags for test.Thanks a lot, Serban! Much appreciated.
Alright thank you everyone for your amazing support. I've managed to solve it in a way I am happy with. Let me clarify what I did and what caused confusion on my part to help anyone in the future dealing with the same issue.
As @siordache pointed out, and what I was not aware of, org.openjfx.javafxplugin automatically applies the gradle-modules-plugin which patches the module. Therefore in my specific case, I didn't further investigate @sormuras provided possible solution as I did not want to mess with the existing automatic configuration.
Thank you both for pointing out the mixture in jUnit dependencies, I know where it comes from (the project contains jUnit 4 tests as well) but using the correct dependencies as pointed out by @siordache you are able to run both jUnit 4 and jUnit5 tests using useJUnitPlatform().
Finally what solved it for me, adding a module-info.java to your main module adds some difficulty with exposing dependencies, ignoring this file would technically work, but is not the nicest solution obviously. So adding the module-info.test is a lot better.
On the topic of module-info.test
org.junit.platform) to be provided by hand to runHopefully this answer has been useful, again thank you!
my IDE (IntelliJ) did not recognize the type and said there was an error ...
IntelliJ will soon add support for module-info.test files: https://youtrack.jetbrains.com/issue/IDEA-222831
Closing this issue as "question-answered". Further discussion should move to Gradle's and/or IJ IDEA's issue tracker.
Most helpful comment
@SSchepers My proposed solution is: "just remove it!" 馃槇
But I'm not talking about the
module-info.javain your main module. The problem is the one in thesrc/test/javadirectory.When doing whitebox testing, you don't want (and, due to split packages, you cannot build) a separate "test module". Instead, for testing purposes, you need to patch your main module with the classes produced by compiling the code in
src/test/java.You use
org.openjfx.javafxplugin, which automatically applies the gradle-modules-plugin. And this plugin patches the main module for you. It also detects the test framework used by your application and configures the necessary compiler flags for it (--add-modules,--add-reads,--add-opens).As pointed by @sormuras, your
build.gradlecontains a strange mixture of JUnit 4 and 5. I'm not sure if thegradle-modules-plugincan handle this correctly.If your tests need to access types from modules not required by your main module, you can pass the necessary additional compiler flags in a
module-info.testfile (this feature has been contributed by @sormuras). For example, if you use AssertJ in your tests, you need to put this in yourmodule-info.test:So, my proposed solution is:
build.gradleand your test code to use only JUnit 5.src/test/java/module-info.javamodule-info.testfile insrc/test/java, with additional compiler flags for test.