How do I add a new sourceset to Gradle?

I want to add integration tests to my Gradle build (Version 1.0). They should run separately from my normal tests because they require a webapp to be deployed to localhost (they test that webapp). The tests should be able to use classes defined in my main source set. How do I make this happen?

Answers


This took me a while to figure out and the online resources weren't great. So I wanted to document my solution.

This is a simple gradle build script that has an intTest source set in addition to the main and test source sets:

apply plugin: "java"

sourceSets {
    // Note that just declaring this sourceset creates two configurations.
    intTest {
        java {
            compileClasspath += main.output
            runtimeClasspath += main.output
        }
    }
}

configurations {
    intTestCompile.extendsFrom testCompile
    intTestRuntime.extendsFrom testRuntime
}

task intTest(type:Test){
    description = "Run integration tests (located in src/intTest/...)."
    testClassesDir = project.sourceSets.intTest.output.classesDir
    classpath = project.sourceSets.intTest.runtimeClasspath
}

Here is how I achieved this without using configurations{ }.

apply plugin: 'java'

sourceCompatibility = JavaVersion.VERSION_1_6

sourceSets {
    integrationTest {
        java {
            srcDir 'src/integrationtest/java'
        }
        resources {
            srcDir 'src/integrationtest/resources'
        }
        compileClasspath += sourceSets.main.runtimeClasspath
    }
}

task integrationTest(type: Test) {
    description = "Runs Integration Tests"
    testClassesDir = sourceSets.integrationTest.output.classesDir
    classpath += sourceSets.integrationTest.runtimeClasspath
}

Tested using: Gradle 1.4 and Gradle 1.6


This was once written for Gradle 2.x / 3.x in 2016 and is far outdated!! Please have a look at the documented solutions in Gradle 4 and up


To sum up both old answers (get best and minimum viable of both worlds):

some warm words first:

  1. first, we need to define the sourceSet:

    sourceSets {
        integrationTest
    }
    
  2. next we expand the sourceSet from test, therefor we use the test.runtimeClasspath (which includes all dependenciess from test AND test itself) as classpath for the derived sourceSet:

    sourceSets {
        integrationTest {
            compileClasspath += sourceSets.test.runtimeClasspath
            runtimeClasspath += sourceSets.test.runtimeClasspath // ***)
        }
    }
    
    • note) somehow this redeclaration / extend for sourceSets.integrationTest.runtimeClasspath is needed, but should be irrelevant since runtimeClasspath always expands output + runtimeSourceSet, don't get it
  3. we define a dedicated task for just running integration tests:

    task integrationTest(type: Test) {
    }
    
  4. Configure the integrationTest test classes and classpaths use. The defaults from the java plugin use the test sourceSet

    task integrationTest(type: Test) {
        testClassesDir = sourceSets.integrationTest.output.classesDir
        classpath = sourceSets.integrationTest.runtimeClasspath
    }
    
  5. (optional) auto run after test

    integrationTest.dependsOn test
    

  6. (optional) add dependency from check (so it always runs when build or check are executed)

    tasks.check.dependsOn(tasks.integrationTest)
    
  7. (optional) add java,resources to the sourceSet to support auto-detection and create these "partials" in your IDE. i.e. IntelliJ IDEA will auto create sourceSet directories java and resources for each set if it doesn't exist:

    sourceSets {
         integrationTest {
             java
             resources
         }
    }
    

tl;dr

apply plugin: 'java'

// apply the runtimeClasspath from "test" sourceSet to the new one
// to include any needed assets: test, main, test-dependencies and main-dependencies
sourceSets {
    integrationTest {
        // not necessary but nice for IDEa's
        java
        resources

        compileClasspath += sourceSets.test.runtimeClasspath
        // somehow this redeclaration is needed, but should be irrelevant
        // since runtimeClasspath always expands compileClasspath
        runtimeClasspath += sourceSets.test.runtimeClasspath
    }
}

// define custom test task for running integration tests
task integrationTest(type: Test) {
    testClassesDir = sourceSets.integrationTest.output.classesDir
    classpath = sourceSets.integrationTest.runtimeClasspath
}
tasks.integrationTest.dependsOn(tasks.test)

referring to:

Unfortunatly, the example code on github.com/gradle/gradle/subprojects/docs/src/samples/java/customizedLayout/build.gradle or …/gradle/…/withIntegrationTests/build.gradle seems not to handle this or has a different / more complex / for me no clearer solution anyway!


The nebula-facet plugin eliminates the boilerplate:

apply plugin: 'nebula.facet'
facets {
    integrationTest {
        parentSourceSet = 'test'
    }
}

For integration tests specifically, even this is done for you, just apply:

apply plugin: 'nebula.integtest'

The Gradle plugin portal links for each are:

  1. nebula.facet
  2. nebula.integtest

If you're using

To get IntelliJ to recognize custom sourceset as test sources root:

plugin {
    idea
}

idea {
    module {
        testSourceDirs = testSourceDirs + sourceSets["intTest"].allJava.srcDirs
        testResourceDirs = testResourceDirs + sourceSets["intTest"].resources.srcDirs
    }
}

Here's what works for me as of Gradle 4.0.

sourceSets {
  integrationTest {
    compileClasspath += sourceSets.test.compileClasspath
    runtimeClasspath += sourceSets.test.runtimeClasspath
  }
}

task integrationTest(type: Test) {
  description = "Runs the integration tests."
  group = 'verification'
  testClassesDirs = sourceSets.integrationTest.output.classesDirs
  classpath = sourceSets.integrationTest.runtimeClasspath
}

As of version 4.0, Gradle now uses separate classes directories for each language in a source set. So if your build script uses sourceSets.integrationTest.output.classesDir, you'll see the following deprecation warning.

Gradle now uses separate output directories for each JVM language, but this build assumes a single directory for all classes from a source set. This behaviour has been deprecated and is scheduled to be removed in Gradle 5.0

To get rid of this warning, just switch to sourceSets.integrationTest.output.classesDirs instead. For more information, see the Gradle 4.0 release notes.


Need Your Help

Where should a beginner start with computer vision?

language-agnostic computer-science computer-vision

I'm an undergrad who finds computer vision to be fascinating. Where should somebody brand new to computer vision begin?

AngularJS:How to indentify which angular code we need to run manually by angular.bootstrap function

angularjs

i am quite new in angular and still learning. so just found today angular.bootstrap function it run ng code manually.