You can open this sample in an IDE that supports Gradle.

This sample shows how to add additional test types to a JVM project in Gradle. Your project may have many different kinds of tests—​unit tests, integration tests, functional tests, etc. A JVM project in Gradle has a single Test task, but other tasks can be added to represent each of these test types.

In this sample, we are testing Java projects with JUnit5; however, this applies to other JVM languages as well.

Concretely, we add a convention plugin in buildSrc to share the integration test setup between multiple subprojects:

buildSrc/src/main/kotlin/myproject.java-conventions.gradle.kts
plugins {
    java
}

version = "1.0.2"
group = "org.gradle.sample"

repositories {
    mavenCentral()
}

val integrationTest by sourceSets.creating

configurations[integrationTest.implementationConfigurationName].extendsFrom(configurations.testImplementation.get())
configurations[integrationTest.runtimeOnlyConfigurationName].extendsFrom(configurations.testRuntimeOnly.get())

tasks.test {
    useJUnitPlatform()
}

val integrationTestTask = tasks.register<Test>("integrationTest") {
    description = "Runs integration tests."
    group = "verification"
    useJUnitPlatform()

    testClassesDirs = integrationTest.output.classesDirs
    classpath = configurations[integrationTest.runtimeClasspathConfigurationName] + integrationTest.output

    shouldRunAfter(tasks.test)
}

tasks.check {
    dependsOn(integrationTestTask)
}

dependencies {
    testImplementation("org.junit.jupiter:junit-jupiter:5.7.1")
    testRuntimeOnly("org.junit.platform:junit-platform-launcher")

    "integrationTestImplementation"(project)
}
buildSrc/src/main/groovy/myproject.java-conventions.gradle
plugins {
    id 'java'
}

version = '1.0.2'
group = 'org.gradle.sample'

repositories {
    mavenCentral()
}

def integrationTest = sourceSets.create('integrationTest')

configurations[integrationTest.implementationConfigurationName].extendsFrom(configurations.testImplementation)
configurations[integrationTest.runtimeOnlyConfigurationName].extendsFrom(configurations.testRuntimeOnly)

tasks.named('test') {
    useJUnitPlatform()
}

def integrationTestTask = tasks.register('integrationTest', Test) {
    description = 'Runs integration tests.'
    group = 'verification'
    useJUnitPlatform()

    testClassesDirs = integrationTest.output.classesDirs
    classpath = configurations[integrationTest.runtimeClasspathConfigurationName] + integrationTest.output

    shouldRunAfter(tasks.named('test'))
}

tasks.named('check') {
    dependsOn(integrationTestTask)
}

dependencies {
    testImplementation 'org.junit.jupiter:junit-jupiter:5.7.1'
    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

    integrationTestImplementation project
}

And apply it in an application project:

application/build.gradle.kts
plugins {
    id("myproject.java-conventions")
    application
}

dependencies {
    implementation(project(":list"))
    implementation(project(":utilities"))
}

application {
    mainClass = "org.gradle.sample.app.Main"
}
application/build.gradle
plugins {
    id 'myproject.java-conventions'
    id 'application'
}

dependencies {
    implementation project(':list')
    implementation project(':utilities')
}

application {
    mainClass = 'org.gradle.sample.app.Main'
}

And in library projects:

utilities/build.gradle.kts
plugins {
    id("myproject.java-conventions")
    `java-library`
}

dependencies {
    implementation(project(":list"))
}
utilities/build.gradle
plugins {
    id 'myproject.java-conventions'
    id 'java-library'
}

dependencies {
    implementation project(':list')
}

These additional tests can be executed with the integrationTest task or as part of lifecycle check:

$ ./gradlew check

BUILD SUCCESSFUL
14 actionable tasks: 14 executed