I have a simple Java 11 project in Eclipse with the following dependencies:
dependencies {
testImplementation("org.junit.jupiter:junit-jupiter-api:${junit}")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${junit}")
}
The project structure is as follows:
The module-info.java only exports the package simple.tests in the module simple.tests.
I have defined the following Gradle tasks for setting up the Eclipse project and its dependencies properly. The test dependencies are on the classpath and these are only visible to the test sources.
eclipse {
classpath {
file {
whenMerged {
entries.findAll {
it.kind == 'src' || it.kind == 'lib'
}.each { it.entryAttributes['module'] = 'true' }
}
}
}
}
eclipse.classpath.file.whenMerged {
// Setting output folder for main files
def mainSrc = entries.find { it.path == 'src/main/java' }
if(mainSrc != null) {
mainSrc.output = 'bin/main'
}
def mainResources = entries.find { it.path == 'src/main/resources' }
if(mainResources != null) {
mainResources.output = 'bin/main'
}
// Setting output folder for test files
def testSrc = entries.find { it.path == 'src/test/java' }
if(testSrc != null) {
testSrc.output = 'bin/test'
testSrc.entryAttributes['test'] = 'true'
testSrc.entryAttributes['module'] = 'false'
}
def testResources = entries.find { it.path == 'src/test/resources' }
if (testResources != null) {
testResources.output = 'bin/test'
testResources.entryAttributes['test'] = 'true'
testResources.entryAttributes['module'] = 'false'
}
// Updating test dependencies' visibility and adding them to module path
// instead of the classpath
entries.forEach { entry ->
def entryIn = { it.find { file(entry.path).equals(it) } }
if (entry.kind == 'lib') {
entry.entryAttributes['test'] =
entryIn(configurations.testRuntimeClasspath) &&
!entryIn(configurations.runtimeClasspath)
if(entry.entryAttributes['test']) {
entry.entryAttributes['module'] = 'false'
}
}
}
}
I am able to compile and run the test cases in Gradle (5.0) with the following settings:
test {
useJUnitPlatform()
}
ext.moduleName = 'simple.tests'
compileJava {
inputs.property("moduleName", moduleName)
doFirst {
options.compilerArgs = [
'--module-path', classpath.asPath,
]
classpath = files()
}
}
However, I can not execute the JUnit test in Eclipse because I get the an error message (No tests found with test runner 'Junit 5') and the following Stack Trace:
Class not found simple.tests.DummyTest
java.lang.ClassNotFoundException: simple.tests.DummyTest
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:583)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.loadClass(RemoteTestRunner.java:773)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.loadClasses(RemoteTestRunner.java:502)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:525)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)
Moving the test dependencies to the module path doesn't solve the problem. In this case I get the following Stack Trace, even after adding Junit Launcher to the module path:
java.lang.NoClassDefFoundError: org/junit/platform/engine/EngineExecutionListener
at org.junit.platform.launcher.core.LauncherFactory.create(LauncherFactory.java:59)
at org.eclipse.jdt.internal.junit5.runner.JUnit5TestLoader.<init>(JUnit5TestLoader.java:34)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
at java.base/java.lang.Class.newInstance(Class.java:584)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.createRawTestLoader(RemoteTestRunner.java:370)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.createLoader(RemoteTestRunner.java:365)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.defaultInit(RemoteTestRunner.java:309)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.init(RemoteTestRunner.java:224)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:208)
Caused by: java.lang.ClassNotFoundException: org.junit.platform.engine.EngineExecutionListener
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:583)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
... 12 more
The only solution I found was removing the module-info.java file. After deleting the module descriptor, the test case(s) can be executed in Eclipse and in Gradle as well.
Is there a wrong setting in my configuration? Or am I doing anything wrong?
Thank you in advance!