Sharing testFixtures among sub-projects and using the gradle wrapper for running tasks

The project I’m working on is structured like this. The folder structure is the same for the projects one, two, and three.

root
├── settings.gradle
├── build.gradle
├── gradlew
└── parent
    ├── one
    │   ├── gradlew
    │   ├── settings.gradle
    │   ├── build.gradle
    │   └── src
    │       ├── integration
    │       ├── main
    │       └── test
    ├── two
    ├── three
    └── shared
        ├── build.gradle
        └── src
            └── testFixtures

The shared project is used only for sharing utility code (from shared/src/testFixtures) among projects one, two, and three. The root/settings.gradle file looks like this. I’m using the java-test-fixtures plugin for this.

include 'parent:one'
include 'parent:two'
include 'parent:three'
include 'parent:shared'

The settings.gradle file for projects one / two / three looks like this

rootProject.name="<name>"
include ":parent:shared"

I have defined a source set and task for integration tests in the build.gradle for projects one, two, and three.

sourceSets {
    integration {
        compileClasspath += sourceSets.main.output
    }
}

configurations {
    integrationImplementation.extendsFrom testImplementation
    integrationRuntimeOnly.extendsFrom testRuntimeOnly
    integrationAnnotationProcessor.extendsFrom testAnnotationProcessor
}

tasks.withType(Test).configureEach {
    useJUnitPlatform()
}

tasks.register("integrationTest", Test) {
    description = "Runs integration tests."
    group = "verification"
    testClassesDirs = sourceSets.integration.output.classesDirs
    classpath = sourceSets.integration.runtimeClasspath
}

Those build.gradle files for the three projects also contains this line

integrationImplementation(testFixtures(project(":parent:shared")))

I want to be able to run my integrationTest task using the gradle wrapper from both the root/ directory, and the subproject directories (e.g., root/parent/one/).

The task runs fine when I run the following command from the root directory

./gradlew clean parent:one:integrationTest

But if I change to a subproject directory (e.g., root/parent/one/), and run the following command

./gradlew clean integrationTest

I get this error

Could not determine the dependencies of task ':integrationTest'.
> Could not resolve all task dependencies for configuration ':integrationRuntimeClasspath'.
   > Could not resolve project :parent:shared.
     Required by:
         project :
      > No matching configuration of project :parent:shared was found. The consumer was configured to find a library for use during runtime, compatible with Java 11, packaged as a jar, preferably optimized for standard JVMs, and its dependencies declared 
externally but:
          - None of the consumable configurations have attributes.

Any way I can fix this? I know I can just use the first option, but I want to know if there’s a configuration that lets me do both. Plus, if I am doing something fundamentally incorrect with my configuration. I know it’s unusual to have multiple gradle wrappers, one for each sub-project, but that’s the way the project was already setup, and is beyond my control.

Would appreciate any help. Thanks.

I must admit I stopped reading after the you showed the settings script contents.
Because what you have there is already extremely bad-practice and should never ever ever be done.
One project should never be part of more than one build.

As you model one, two, and three as stand-alone builds, you should not also include those project in the root project. And you should not include the shared project in more than one build. That just brings a s***load of problems and strange behavior.

To compose mutliple stand-alone builds, use composite build feature (includeBuild) where you include whole builds and then declare the necessary dependencies using normal coordinates instead of project dependencies.

Without even having read further, chances are high you solve whatever problem you have currently. :slight_smile:

Thanks for the response. Shortly after posting my question, I read this on stackoverflow. Following that, I tried deleting the settings.gradle file for projects one, two, and three. That actually solved my problem. I am not sure if these projects were designed to be stand-alone builds, but that’s something I need to ask from other personnel on my team, and not the internet.

Would this still be bad practice if I went the route of deleting the three settings.gradle file and then just used the following in the build.gradle for the three sub-projects

integrationImplementation(testFixtures(project(":parent:shared")))

No, that should then be fine, if all four projects are part of the same multi-project build, using a project dependency is exactly the right thing to do.

1 Like