1

I have a following Gradle project structure:

project-root/
├── adapters/
│   ├── adapter1/
│   │   ├── main
│   │   └── test
│   ├── adapter2/
│   │   ├── main
│   │   └── test
│   └── adapter3/
│       ├── main
│       └── test
└── app-spring-boot/
    ├── main
    ├── test
    └── integrationTest

In the app-spring-boot module, the adapters are included only as runtime dependency:

// project-root/app-spring-boot/build.gradle.kts
dependencies {
    runtimeOnly(project(":adapters:adapter1")
    runtimeOnly(project(":adapters:adapter2")
    runtimeOnly(project(":adapters:adapter3")
}

In the app-spring-boot module for integrationTest source set, I would like to be able to access all dependencies at compile time not only directly from app-spring-boot, but from all of the included :adapters projects as well.

I've used following configuration:

// project-root/app-spring-boot/build.gradle.kts
plugins {
    `jvm-test-suite`
}

testing {
    suites {
        val test by getting(JvmTestSuite::class)

        val integrationTest by registering(JvmTestSuite::class) {
            useJUnitJupiter()
            dependencies {
                implementation(project())
            }
            sources {
                compileClasspath += sourceSets.main.get().runtimeClasspath
            }
        }
    }
}

compileClasspath += sourceSets.main.get().runtimeClasspath does the trick and all dependencies from included runtimeOnly projects are accessible at compile time, but I'm wondering what it is the correct and idiomatic Gradle way of doing it, especially since I saw @chalimartines comment.

adriangl1997
  • 57
  • 1
  • 6

1 Answers1

1

I agree with the comment you found, saying that adding to the compile classpath is not the right way as you end up with duplicated dependencies.

When applying the test suites plugin, it will create a set of configurations similar to the ones from the main and test source sets, prefixed with the name of the test suite. Because your test suite is called integrationTest, the "implementation" configuration is named integrationTestImplementation.

With this, you can add the runtime dependencies to the compile classpath by making this implementation configuration of the test suite extend the regular runtimeClasspath configuration from the main source set. E.g.:

testing {
    // ...
}

configurations["integrationTestImplementation"].extendsFrom(configurations["runtimeClasspath"])
Bjørn Vester
  • 6,851
  • 1
  • 20
  • 20
  • Thanks for the answer, but unfortunately this solution doesn't seem to work. I've got compile errors with unresolved references. Correct me if I'm wrong, but as far as I understand your solution included removing `compileClasspath += sourceSets.main.get().runtimeClasspath`? – adriangl1997 Feb 02 '23 at 16:14
  • On further inspection, I found out that your solution does actually work for direct dependencies. So, for example, a class I declared in `:adapters:adapter1` project will be accessible in `integrationTest` source set. I'm sorry if I wasn't clear, but what I want to achieve is to be able to access transitive dependencies as well. Is it possible by extending configuration? – adriangl1997 Feb 02 '23 at 17:06
  • Are those transitive dependencies declared as "implementation" in the adapter projects? Because those will always be hidden from consumers. I don't know of an easy way to expose those, except to make them 'api' dependencies instead (using the java-library plugin). – Bjørn Vester Feb 03 '23 at 09:37
  • Yes, they are declared as `implementation`. – adriangl1997 Feb 03 '23 at 10:08