vscode-java icon indicating copy to clipboard operation
vscode-java copied to clipboard

Depending on a gradle testFixtures module generates java build problems

Open Frank-D opened this issue 3 years ago • 15 comments
trafficstars

Hi, I have a multi-modules gradle/java project in which I'm trying to centralize some test fixtures (aka test helper classes to help build test data etc) in some kind of library module, so that those java test fixtures classes can then be shared in multiple dependant modules (I'm referring precisely to this gradle test fixtures feature).

The problem I'm having in VS Code (with the Java extension) is that once I've defined my test fixtures in the lib module (see steps to reproduce below), as soon as I try to "consume" them by adding the dependency in a gradle dependant module build file (as explained here in gradle doc), something like:

dependencies {
    implementation(project(":lib-module"))

    testImplementation(testFixtures(project(":lib-module")))
}

it will create compile errors under the vs code Problems tab that the dependant module can no longer see any dependency imports made by the basic implementation(project(":lib-module")).

However, if I build everything with gradle, it will work just fine. The reported compile errors are only visual, within the Problems tab of the vscode editor.

Then, if I comment out the gradle testFixtures dependency import as follow:

dependencies {
    implementation(project(":lib-module"))

    //testImplementation(testFixtures(project(":lib-module")))
}

all compile errors will be gone from the vs code Problems tab, BUT, then if I try to run a gradle build task, it will fail saying that my tests no longer have access to the test fixtures imports from the lib module.

This seems to me like an issue with the vscode-java extension (or upstream?) not supporting properly the gradle testFixtures feature, preventing us from sharing in a very simple way test fixtures among multiple modules.

Environment

Operating System: macOS big sur (11.6.5) JDK version: openjdk version "17.0.4.1" 2022-08-12 Visual Studio Code version: 1.71.0 Java extension version: 1.12.0

Steps To Reproduce
  1. Create a multi-modules gradle java project (2 modules should be enough, the lib exposing both normal lib utility/service classes and also test fixtures)
  2. Create one normal utility class in the lib module, can be just a simple pojo... (<lib-module>/src/main/java/com/...)
  3. Create one test fixture class also under the lib module, can be just a simple pojo... (<lib-module>/src/testFixture/java/com/...)
  4. Add the gradle test Fixtures plugin under your lib gradle build file (<lib-module>/build.gradle)
plugins {
    // A Java Library
    id 'java-library'
    // which produces test fixtures
    id 'java-test-fixtures'
}
  1. In the second dependant module, create one normal class that will consume/import the utility class from the lib module created in step 2 (<dependant-module>/src/main/java/com/...)
  2. In the second dependant module, create a test class that will consume/import the test fixture class from the lib module created in step 3 (<dependant-module>/src/test/java/com/...), the test class can just be a simple pojo, no need to import any test framework for this, we're just testing dependencies between gradle modules...
  3. Add the dependencies under the dependant module's gradle build file, so that it sees both the utility class AND the test fixture class from the lib module (<dependant-module>/build.gradle):
dependencies {
    implementation(project(":lib-module"))

    testImplementation(testFixtures(project(":lib-module")))
}
  1. Save everything, and you should expect to see compile errors in the vs code Problems tab, complaining about the fact that your dependant module's normal pojo class created in step 5 is unable to import the utility class from the lib module (that's right, the error might not even be inside your test class, but it could, it all depends where you've imported the lib utility class in this example, whether it's within the normal class in step 5, but it could have been under your test class of step 6 too; bottom line is, the compile error will be related to the normal lib classes that can no longer be imported in the dependant module(s); the test fixtures classes 'are' being imported properly.. So it really seems like if importing the 'test fixtures' will PREVENT the normal lib classes from being imported).

Sample project

I've created this basic sample project which reproduces the error: https://github.com/Frank-D/multi-modules-root

Current Result

Compile errors showing under vs code Problems tab (e.g., using gradle test fixtures lib dependency hides the basic lib module dependency).

Expected Result

No compile errors showing under vs code Problems tab (e.g. using gradle test fixtures works without any issue within vs code using the vscode-java extension).

Additional Informations

Here's a screenshot of the vs code Problems, when reproducing the described error with the previous 'Sample project': vscode_gradle-for-java_testfixtures-error

Frank-D avatar Nov 06 '22 16:11 Frank-D

It is an upstream buildship issue. I can reproduce it in Eclipse. See https://github.com/eclipse/buildship/issues/991

@Frank-D You can try the following patch:

diff --git a/module-a-testfixtures/build.gradle b/module-a-testfixtures/build.gradle
index e488f01..9c92bac 100644
--- a/module-a-testfixtures/build.gradle
+++ b/module-a-testfixtures/build.gradle
@@ -1,6 +1,7 @@
 plugins {
 	id 'java-library'
 	id 'java-test-fixtures' // to export java test helper/data "fixture" classes for other projects to re-use in their tests...
+	id 'eclipse'
 }
 
 group = 'com.reproduce.testfixtures.uc.moda'
@@ -19,10 +20,16 @@ dependencies {
 
 }
 
-// sourceSets {
-//     main {
-//         java {
-//             srcDir 'src/main/java'
-//         }
-//     }
-// }
+eclipse.classpath.file.whenMerged {
+        def test = entries.find { it.path == 'src/test/java' }
+        if (test) {
+            test.entryAttributes['gradle_used_by_scope'] = 'main, test'
+            test.entryAttributes['test'] = 'false'
+        }
+        def testFixtures = entries.find { it.path == 'src/testFixtures/java' }
+        if (testFixtures) {
+            testFixtures.entryAttributes['gradle_used_by_scope'] = 'main, test'
+            testFixtures.entryAttributes['test'] = 'false'
+        }
+    } 
+
diff --git a/module-b-dependson-a/build.gradle b/module-b-dependson-a/build.gradle
index 593f6d7..9b95cec 100644
--- a/module-b-dependson-a/build.gradle
+++ b/module-b-dependson-a/build.gradle
@@ -1,5 +1,6 @@
 plugins {
 	id 'java-library' // to enable the use of 'api' dependencies and export those to other dependant projects
+	id 'eclipse'
 }
 
 group = 'com.reproduce.testfixtures.uc.modb'
@@ -19,3 +20,17 @@ dependencies {
 
 	testImplementation(testFixtures(project(":module-a-testfixtures")))
 }
+
+eclipse.classpath.file.whenMerged {
+		cp -> cp.getEntries().forEach{
+			cpEntry -> if(cpEntry.path=='/module-a-testfixtures') {
+				cpEntry.entryAttributes['test'] = 'false'
+			}
+        }
+        def test = entries.find { it.path == 'src/test/java' }
+        if (test) {
+            test.entryAttributes['gradle_used_by_scope'] = 'main, test'
+            test.entryAttributes['test'] = 'false'
+        }
+    }
+
diff --git a/module-c-dependson-b/build.gradle b/module-c-dependson-b/build.gradle
index c9e6d58..f30f7a1 100644
--- a/module-c-dependson-b/build.gradle
+++ b/module-c-dependson-b/build.gradle
@@ -1,5 +1,6 @@
 plugins {
 	id 'java'
+	id 'eclipse'
 }
 
 group = 'com.reproduce.testfixtures.uc.modc'
@@ -19,3 +20,16 @@ dependencies {
 
 	testImplementation(testFixtures(project(":module-a-testfixtures")))
 }
+
+eclipse.classpath.file.whenMerged {
+			cp -> cp.getEntries().forEach{
+				cpEntry -> if(cpEntry.path=='/module-a-testfixtures') {
+					cpEntry.entryAttributes['test'] = 'false'
+				}
+            }
+        def test = entries.find { it.path == 'src/test/java' }
+        if (test) {
+            test.entryAttributes['gradle_used_by_scope'] = 'main, test'
+            test.entryAttributes['test'] = 'false'
+        }
+    }

snjeza avatar Nov 07 '22 17:11 snjeza

Thanks @snjeza for your response and sharing the patch..

I ended up using another alternative approach, which is described here, and it works really well.

Obviously, I would have preferred to leverage the gradle 'java-test-fixtures' plugin and have it working in vscode, but that previous linked alternative solution is acceptable, and cleaner/simpler imo than the above patch which exposes lots of internal details.


Regarding the eclipse issue that you've linked, I'm not sure I fully understand it, because it is closed and basically saying that the fix was done inside gradle v6.8, suggesting that the issue is not with eclipse/buildship...but in the end, I am using gradle 7.5 with vscode and vscode-java, and gradle testFixtures feature is not working...

Frank-D avatar Nov 18 '22 23:11 Frank-D

Same issue here. Works all finde with IntelliJ. VScode whatsoever produces can not be resolved in the main source set, altought it is navigateable.

This problem occures as soon as I import testFixtures to either the test source set or the test fixture source set. When both dependencies removed, the main source set builds fine again. As said, running gradle from the console has no issues. So doesn't IntelliJ. It only appears with the vscode java plugin. I rather don't want to clutter up my gradle.build file with eclipse stuff only to make it in vsc work. As I'm the only in my team that works with VSC, this might tip the possibility to continue with VSC

Does not build

dependencies {
    implementation project(':subproject')

      # either of the two brakes the main compilation
    testImplementation(testFixtures(project(':subproject')))
    testFixturesImplementation(testFixtures(project(':subproject')))
}

does build

dependencies {
    implementation project(':subproject')

    # testImplementation(testFixtures(project(':subproject')))
    # testFixturesImplementation(testFixtures(project(':subproject')))
}

HerrDerb avatar Nov 23 '22 08:11 HerrDerb

Downgrading gradle wrapper from 7.5.1 to 7.4.2 resolved a simular problem for me.

Uda4nik avatar Nov 23 '22 09:11 Uda4nik

@Uda4nik Thank you, I can confirm this! Downgrading the wrapper from 7.5.1 to 7.4.2 removes the issue. This means that there most possibly is a change in gradle which might not be adapted in the vsc java plugin correctly.

HerrDerb avatar Nov 23 '22 09:11 HerrDerb

Here a very basic project, that reproduces the issue that only occures with gradle 7.5.1, but not with gradle 7.4.2 https://github.com/HerrDerb/gradleTestFixtureIssue

HerrDerb avatar Nov 23 '22 13:11 HerrDerb

One more solution: https://marketplace.visualstudio.com/items?itemName=ASF.apache-netbeans-java can handle Gradle properly.

Uda4nik avatar Dec 09 '22 10:12 Uda4nik

I can reproduce this issue in eclipse. Looks like an issue related to buildship.

CsCherrYY avatar Dec 12 '22 02:12 CsCherrYY

I can reproduce it also with testFixtures (not using it in the main source set though, as stated in the linked buildship issue), and also that downgrading to 7.4.2 fixes it for our setup. Also as already stated the buildship issue is closed, yet the problem persists, so it might be not related.

EDIT found the related gradle issue and an explanation why it happens https://github.com/gradle/gradle/issues/21853

stefanrybacki avatar Dec 24 '22 17:12 stefanrybacki

https://github.com/gradle/gradle/pull/28556 probably fixes this issue.

donat avatar Apr 19 '24 11:04 donat

I can confirm that the current gradle nightly 8.10-20240616002856+0000 resolves this particular issue with test fixtures for me on jdtls / buildship.

appleseedexm avatar Jun 17 '24 07:06 appleseedexm

I can also confirm that the issue is fixed with the 8.9 nightly 8.9-20240607003743+0000, so it will probably be included in 8.9 RC's and the upcoming Gradle 8.9.

thomasredlin avatar Jun 17 '24 13:06 thomasredlin

So is this solved in 8.9?

nlisker avatar Aug 12 '24 19:08 nlisker

This seems to be fixed in the 8.10.1 binary. Not sure which was the first official version that contains the fix, but I think this issue can be closed.

appleseedexm avatar Sep 19 '24 12:09 appleseedexm

The fix for this issue and the relevant Gradle issues https://github.com/gradle/gradle/issues/21968 and https://github.com/gradle/gradle/issues/22838 were released with Gradle 8.9 (release notes).

@Frank-D Could you verify this and close the issue?

oleosterhagen avatar Sep 20 '24 18:09 oleosterhagen