# 7.3 test suite: inherit test libraries for integration test

**URL:** <https://discuss.gradle.org/t/7-3-test-suite-inherit-test-libraries-for-integration-test/41980>\
**Category:** Help/Discuss\
**Created:** [January 18, 2022, 9:36am UTC](https://discuss.gradle.org/t/7-3-test-suite-inherit-test-libraries-for-integration-test/41980 "2022-01-18T09:36:11Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![C-Otto](https://sea1.discourse-cdn.com/gradle/user_avatar/discuss.gradle.org/c-otto/32/8680_2.png) [@C-Otto](https://discuss.gradle.org/u/C-Otto)\
**Post date:** [January 18, 2022, 9:36am UTC](https://discuss.gradle.org/t/7-3-test-suite-inherit-test-libraries-for-integration-test/41980/1 "2022-01-18T09:36:11Z")

</div>

I’d love to use the new test suite feature to define a new test suite for my integration tests. Previously, I defined a new source set and defined the configuration manually:

```gradle
sourceSets {
    integrationTest {
        compileClasspath += sourceSets.main.output
        runtimeClasspath += sourceSets.main.output
    }
}

configurations {
    integrationTestImplementation.extendsFrom testImplementation
    integrationTestRuntimeOnly.extendsFrom testRuntimeOnly
}

task integrationTest(type: Test) {
    description = 'Runs integration tests.'
    group = 'verification'

    testClassesDirs = sourceSets.integrationTest.output.classesDirs
    classpath = sourceSets.integrationTest.runtimeClasspath
    shouldRunAfter test
}

```

With the test suite plugin, this should look something like this:

```gradle
testing {
    suites {
        integrationTest(JvmTestSuite) {
            testType = TestSuiteType.INTEGRATION_TEST
            dependencies {
                implementation project
                implementation XXX
            }

            targets {
                all {
                    testTask.configure {
                        shouldRunAfter(test)
                    }
                }
            }
        }
    }
}

```

However, I don’t know how I can inherit the libraries from my test task. For example, my tests depend on AssertJ, and I’d love to inherit this dependency. I don’t mind depending on the actual test implementation, too, although that’s not necessary.

---

<div class="post-metadata">

**Author:** ![Vampire](https://sea1.discourse-cdn.com/gradle/user_avatar/discuss.gradle.org/vampire/32/9082_2.png) [@Vampire](https://discuss.gradle.org/u/Vampire)\
**Post date:** [January 19, 2022, 10:53am UTC](https://discuss.gradle.org/t/7-3-test-suite-inherit-test-libraries-for-integration-test/41980/2 "2022-01-19T10:53:17Z")

</div>

I’d say same way

```groovy
configurations {
    integrationTestImplementation.extendsFrom testImplementation
}

```

---

<div class="post-metadata">

**Author:** ![sterling](https://sea1.discourse-cdn.com/gradle/user_avatar/discuss.gradle.org/sterling/32/5395_2.png) [@sterling](https://discuss.gradle.org/u/sterling)\
**Post date:** [January 20, 2022, 11:03pm UTC](https://discuss.gradle.org/t/7-3-test-suite-inherit-test-libraries-for-integration-test/41980/3 "2022-01-20T23:03:38Z")

</div>

I would go a different way. There’s no reason for `testImplementation` and `integrationTestImplementation` to have some kind of relationship. You need to know the names of the configurations and you have to drop out of the context of “testing” to define it.

Just explicitly say that “all JVM test suites have a dependency on XXX”:

```gradle
testing {
    suites {
        withType(JvmTestSuite) {
            dependencies {
                implementation XXX
            }
        }
    }
}

```

Or duplicate the dependency into each test suite declaration.

We don’t support it now, but I don’t see why we couldn’t also allow:

```gradle
testing {
    suites {
        configure(test, integrationTest) {
            dependencies {
                implementation "XXX"
            }
        }
    }
}

```

---

<div class="post-metadata">

**Author:** ![C-Otto](https://sea1.discourse-cdn.com/gradle/user_avatar/discuss.gradle.org/c-otto/32/8680_2.png) [@C-Otto](https://discuss.gradle.org/u/C-Otto)\
**Post date:** [January 22, 2022, 10:33pm UTC](https://discuss.gradle.org/t/7-3-test-suite-inherit-test-libraries-for-integration-test/41980/4 "2022-01-22T22:33:40Z")

</div>

Thank you, that looks much nicer! However, follow-up issue: in my integration tests I don’t have access to transitive dependencies from my project. However, strangely, this isn’t an issue with the default test task.

Project `:project-b` has a dependency `implementation project(':project-a')`. A class that is declared in `src/main/java` of `:project-a` can be used from a test in `src/test/java` in “project-b”. However, this class is not available from within the integrationTest in `src/integrationTest/java` in “project-b”.

This is my test/integration test configuration:

```gradle
testing {
    suites {
        test {
            useJUnitJupiter()
        }
        withType(JvmTestSuite) {
            dependencies {
                implementation '(some library)'
            }
        }
        integrationTest(JvmTestSuite) {
            testType = TestSuiteType.INTEGRATION_TEST
            dependencies {
                implementation project
            }
        }
    }
}

```

Where does the (implicit?) dependency for “test” come from? How can I add the same for “integrationTest”?

The implicit test dependency shows up as the first entry in “testCompileClasspath”. This entry is missing for “integrationTest”.

---

<div class="post-metadata">

**Author:** ![C-Otto](https://sea1.discourse-cdn.com/gradle/user_avatar/discuss.gradle.org/c-otto/32/8680_2.png) [@C-Otto](https://discuss.gradle.org/u/C-Otto)\
**Post date:** [January 23, 2022, 9:29pm UTC](https://discuss.gradle.org/t/7-3-test-suite-inherit-test-libraries-for-integration-test/41980/5 "2022-01-23T21:29:42Z")

</div>

According to this integration test, the “test” task automatically gets transitive dependencies which appear in testCompileClassPath. This does not happen for non-default tasks, even if the “implementation project” dependency is given explicitly.

> <https://github.com/gradle/gradle/blob/master/subprojects/testing-jvm/src/integTest/groovy/org/gradle/testing/testsuites/TestSuitesDependenciesIntegrationTest.groovy#L104>

---

<div class="post-metadata">

**Author:** ![C-Otto](https://sea1.discourse-cdn.com/gradle/user_avatar/discuss.gradle.org/c-otto/32/8680_2.png) [@C-Otto](https://discuss.gradle.org/u/C-Otto)\
**Post date:** [January 23, 2022, 9:49pm UTC](https://discuss.gradle.org/t/7-3-test-suite-inherit-test-libraries-for-integration-test/41980/6 "2022-01-23T21:49:47Z")

</div>

And I guess this is the code where “test” gets the magic dependencies:

> <https://github.com/gradle/gradle/blob/2cb4012f55636266937b504cf580c1077c070969/subprojects/plugins/src/main/java/org/gradle/api/plugins/jvm/internal/DefaultJvmVariantBuilder.java#L218>

Looks like I have to do that manually for integrationTest?

---

<div class="post-metadata">

**Author:** ![Tom\_Tresansky](https://sea1.discourse-cdn.com/gradle/user_avatar/discuss.gradle.org/tom_tresansky/32/9360_2.png) [@Tom\_Tresansky](https://discuss.gradle.org/u/Tom_Tresansky)\
**Post date:** [January 28, 2022, 9:18pm UTC](https://discuss.gradle.org/t/7-3-test-suite-inherit-test-libraries-for-integration-test/41980/7 "2022-01-28T21:18:46Z")

</div>

> Looks like I have to do that manually for integrationTest?

Yes, this is by design. The default test suite preserves existing behavior of the test task, custom test suites will require these deps to be specified explicitly. We were hoping to enable flexibility with this, as some custom suites may not require these transitive deps.

---

<div class="post-metadata">

**Author:** ![C-Otto](https://sea1.discourse-cdn.com/gradle/user_avatar/discuss.gradle.org/c-otto/32/8680_2.png) [@C-Otto](https://discuss.gradle.org/u/C-Otto)\
**Post date:** [January 28, 2022, 10:46pm UTC](https://discuss.gradle.org/t/7-3-test-suite-inherit-test-libraries-for-integration-test/41980/8 "2022-01-28T22:46:37Z")

</div>

OK, thank you for the clarification. I guess there are good reasons for this. However, I’d love to have a shortcut to (explicitly) copy the behaviour that “test” has, maybe something like “implementation transitive(project)”.

---

<div class="post-metadata">

**Author:** ![marcschumacher](https://sea1.discourse-cdn.com/gradle/user_avatar/discuss.gradle.org/marcschumacher/32/9666_2.png) [@marcschumacher](https://discuss.gradle.org/u/marcschumacher)\
**Post date:** [February 2, 2022, 4:00pm UTC](https://discuss.gradle.org/t/7-3-test-suite-inherit-test-libraries-for-integration-test/41980/9 "2022-02-02T16:00:20Z")

</div>

Hey, I stepped across the same “problem”. Actually I have created a build file which uses the `jvm-test-suite`, but the dependencies coming from the project are actually not used, as the dependencies from the main project are not found in the step of compiling the integration test. Now I was asking myself how exactly I can make this happen.  
Do you have a code snippet for me that should work? I am pretty new to Gradle and especially this plugin, but I would love to use it as probably this is the last step missing in my configuration.

---

<div class="post-metadata">

**Author:** ![EarthCitizen](https://avatars.discourse-cdn.com/v4/letter/e/5f9b8f/32.png) [@EarthCitizen](https://discuss.gradle.org/u/EarthCitizen)\
**Post date:** [February 2, 2022, 10:44pm UTC](https://discuss.gradle.org/t/7-3-test-suite-inherit-test-libraries-for-integration-test/41980/10 "2022-02-02T22:44:01Z")

</div>

I also recently ran into this problem, and I came up with a way to extend one test suite from another. The code below does exactly that. It is a little hacky in the way that it auto-discovers which configurations to extend with which ones, but it works. I am not sure how to determine which configurations belong to which test tasks without matching on the generated configuration names. This matches up the configuration names with the name of the test tasks removed.

I hope that the Gradle team will come up with a cleaner way to do this via the DSL.

In a util file in buildSrc:

```gradle
import org.gradle.api.PolymorphicDomainObjectContainer
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.plugins.jvm.JvmTestSuite
import org.gradle.api.tasks.testing.Test
import org.gradle.kotlin.dsl.NamedDomainObjectContainerScope
import org.gradle.kotlin.dsl.RegisteringDomainObjectDelegateProviderWithTypeAndAction
import org.gradle.kotlin.dsl.invoke
import org.gradle.testing.base.TestSuite

private fun extendFromConfigs(
    suiteToExtendFrom: JvmTestSuite,
    reuseSrc: Boolean = false,
    subAction: JvmTestSuite.() -> Unit
): JvmTestSuite.() -> Unit {
    var extendFromProject: Project? = null
    var extendFromConfigMap: Map<String, Configuration>? = null
    var extendFromTask: Test? = null

    suiteToExtendFrom.targets {
        all {
            extendFromTask = testTask.get()
            extendFromProject = extendFromTask!!.project
            extendFromConfigMap = configMapFor(extendFromProject!!, extendFromTask!!)
        }
    }

    return {
        useJUnitJupiter()

        dependencies {
            implementation(extendFromProject)
        }

        if (reuseSrc) {
            sources.java.setSrcDirs(suiteToExtendFrom.sources.java.srcDirs)
            sources.resources.srcDirs(suiteToExtendFrom.sources.resources.srcDirs)
        }

        targets {
            all {
                testTask {
                    val extendedConfigMap = configMapFor(this.project, this)
                    extendedConfigMap.forEach {(name, config) ->
                        config.extendsFrom(extendFromConfigMap!![name])
                    }
                    dependsOn(project.tasks.getByName("${extendFromTask!!.name}Classes"))
                    if (reuseSrc) {
                        this.testClassesDirs = extendFromTask!!.testClassesDirs
                    }
                }
            }
        }
        this.apply(subAction)
    }
}

private fun configMapFor(project: Project, testTask: Test): Map<String, Configuration> {
    val configMap = mutableMapOf<String, Configuration>()

    project.configurations.forEach { config ->
        if (config.name.startsWith(testTask.name)) {
            configMap[config.name.removePrefix(testTask.name)] = config
        }
    }

    return configMap
}

fun <T : TestSuite, C : PolymorphicDomainObjectContainer<T>> C.registeringExtended(
    suiteToExtend: JvmTestSuite,
    reuseSrc: Boolean = false,
    action: JvmTestSuite.() -> Unit
): RegisteringDomainObjectDelegateProviderWithTypeAndAction<out C, JvmTestSuite> =
    RegisteringDomainObjectDelegateProviderWithTypeAndAction.of(this, JvmTestSuite::class, extendFromConfigs(suiteToExtend, reuseSrc, action))

```

Then in build.gradle.kts, to run the same tests with different dependencies (registeringExtended gets “false” to not reuse the same test classes, but only share dependencies):

```gradle
testing {
    suites {
        val test by getting(JvmTestSuite::class) {
            useJUnitJupiter()
        }

        val testOther by registeringExtended(test, true) {
            dependencies {
                implementation("other:depencency:1.0.0")
            }
        }

        project.tasks.named("check") {
            dependsOn(testOther)
        }
    }
}

```
