Comment ajouter un nouvel ensemble de sources à Gradle?

99

Je souhaite ajouter des tests d'intégration à ma version Gradle (version 1.0). Ils doivent s'exécuter séparément de mes tests normaux car ils nécessitent le déploiement d'une application Web sur localhost (ils testent cette application Web). Les tests devraient pouvoir utiliser les classes définies dans mon ensemble de sources principal. Comment y parvenir?

Spina
la source

Réponses:

114

Cela m'a pris du temps à comprendre et les ressources en ligne n'étaient pas géniales. J'ai donc voulu documenter ma solution.

Il s'agit d'un simple script de construction gradle qui a un ensemble de sources intTest en plus des ensembles de sources principal et de test:

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
}
Spina
la source
7
Vous devrez toujours déclarer et configurer une tâche de test d'intégration. En termes de documentation, il existe un java/withIntegrationTestséchantillon dans la distribution Gradle complète.
Peter Niederwieser
Merci @PeterNiederwieser J'ai corrigé mon exemple de script de construction.
Spina
2
J'essayais de le faire aussi ... merci beaucoup d'avoir posté la solution :)
Igor Popov
@PeterNiederwieser Merci - pourriez-vous s'il vous plaît le relier? Je trouve également que cette situation exacte manque cruellement dans la documentation: tout est bien et bien de définir un nouveau sourceSet, mais aucune information sur "l'intégrer dans" les cibles réelles de compilation, jar, test et autres - comme le fait cet exemple (sauf pour l'ajout dans le pot, ou en créant un nouveau pot, à partir de ce sourceSet).
stolsvik
À la ligne 6, j'obtiens "Impossible de résoudre le symbole 'java'" lors de l'utilisation d'IntelliJ. Des pensées sur pourquoi?
Snekse
33

Voici comment j'ai réalisé cela sans utiliser 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
}

Testé avec: Gradle 1.4 et Gradle 1.6

Mike Rylander
la source
2
Merci d'avoir partagé! Il est bon de voir des implémentations alternatives.
Spina
1
alors que ce java { srcDir 'src/integrationtest/java' } resources { srcDir 'src/integrationtest/resources' }n'est pas pertinent car il se redéclare simplement src/<sourceSetName>/...à src/integrationtest/...: ici: changer le T majuscule en un t inférieur
childno͡.de
Méfiez-vous de cette approche. compileClasspath += sourceSets.main.runtimeClasspathcombine deux ensembles de fichiers. Il n'y a pas de résolution de conflit habituelle pour les dépendances. Vous pouvez vous retrouver avec deux versions de la même bibliothèque. L'extension des configurations aidera à cela.
chalimartines le
20

Cela a été écrit une fois pour Gradle 2.x / 3.x en 2016 et est loin d'être dépassé !! Veuillez jeter un œil aux solutions documentées dans Gradle 4 et plus


Pour résumer les deux anciennes réponses (obtenir le meilleur et le minimum viable des deux mondes):

quelques mots chaleureux d'abord:

  1. tout d'abord, nous devons définir le sourceSet :

    sourceSets {
        integrationTest
    }
  2. Ensuite, nous développons le sourceSetfrom test, donc nous utilisons le test.runtimeClasspath(qui inclut toutes les dépendances de testAND testlui - même) comme chemin de classe pour le dérivé sourceSet:

    sourceSets {
        integrationTest {
            compileClasspath += sourceSets.test.runtimeClasspath
            runtimeClasspath += sourceSets.test.runtimeClasspath // ***)
        }
    }
    • note ) d'une manière ou d'une autre, cette redéclaration / extension pour sourceSets.integrationTest.runtimeClasspathest nécessaire, mais ne devrait pas être pertinente car se runtimeClasspathdéveloppe toujours output + runtimeSourceSet, ne l'obtenez pas
  3. nous définissons une tâche dédiée pour simplement exécuter des tests d'intégration:

    task integrationTest(type: Test) {
    }
  4. Configurez les integrationTestclasses de test et les chemins de classe utilisés. Les valeurs par défaut du javaplugin utilisent letest sourceSet

    task integrationTest(type: Test) {
        testClassesDir = sourceSets.integrationTest.output.classesDir
        classpath = sourceSets.integrationTest.runtimeClasspath
    }
  5. (optionnel) exécution automatique après test

    integrationTest.dependsOn test
    

  6. (facultatif) ajouter une dépendance de check(donc il s'exécute toujours quand buildou checkest exécuté)

    tasks.check.dependsOn(tasks.integrationTest)
  7. (facultatif) ajoutez java, des ressources au sourceSetpour prendre en charge la détection automatique et créez ces "partiels" dans votre IDE. ie IntelliJ IDEA créera automatiquement des sourceSetrépertoires java et des ressources pour chaque ensemble s'il n'existe pas:

    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)

se référant à:

Malheureusement, l'exemple de code sur github.com/gradle/gradle/subprojects/docs/src/samples/java/customizedLayout/build.gradle ou … / gradle /… / withIntegrationTests / build.gradle ne semble pas gérer cela ou en a un autre / plus complexe / pour moi pas de solution plus claire de toute façon!

childno͡.de
la source
1
(!) Il s'avère que l'utilisation unique des améliorations de sourceSet sans configuration ni sortie entraîne une erreur de création d'idée après l'ouverture initiale d'un projet. la dépendance de construction (ici: test) pour le nouveau "module" (ici: integrationTest) n'est pas disponible pour la première foiscompileTestJava
childno͡.de
2
classesDira été migré vers classesDirsle grade 5
deFreitas
merci pour l'indice @deFreitas, j'ai marqué la réponse comme obsolète
childno͡.de
9

Le plugin nebula-facet élimine le passe-partout:

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

Pour les tests d'intégration en particulier, même cela est fait pour vous , il suffit d'appliquer:

apply plugin: 'nebula.integtest'

Les liens du portail du plugin Gradle pour chacun sont:

  1. nebula.facet
  2. nebula.integtest
jkschneider
la source
7

Si vous utilisez

Pour qu'IntelliJ reconnaisse l'ensemble de sources personnalisé en tant que racine des sources de test:

plugin {
    idea
}

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

Voici ce qui fonctionne pour moi à partir de 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
}

Depuis la version 4.0, Gradle utilise désormais des répertoires de classes séparés pour chaque langue d'un ensemble source. Donc, si votre script de construction utilise sourceSets.integrationTest.output.classesDir, vous verrez l'avertissement de désapprobation suivant.

Gradle utilise désormais des répertoires de sortie distincts pour chaque langage JVM, mais cette version suppose un répertoire unique pour toutes les classes d'un ensemble source. Ce comportement est obsolète et doit être supprimé dans Gradle 5.0

Pour vous débarrasser de cet avertissement, passez simplement à sourceSets.integrationTest.output.classesDirs. Pour plus d'informations, consultez les notes de publication de Gradle 4.0 .

Ryan Sobol
la source
passer à <hmm> ?? Votre avant et après sont les mêmes.
Merk
0

Je suis nouveau sur Gradle, en utilisant Gradle 6.0.1 JUnit 4.12. Voici ce que j'ai proposé pour résoudre ce problème.

apply plugin: 'java'
repositories { jcenter() }

dependencies {
    testImplementation 'junit:junit:4.12'
}

sourceSets {
  main {
    java {
       srcDirs = ['src']
    }
  }
  test {
    java {
      srcDirs = ['tests']
    }
  }
}

Notez que la source principale et la source de test sont référencées séparément, une sous mainet une sous test.

L' testImplementationélément ci-dessous dependenciesest uniquement utilisé pour compiler la source dans test. Si votre code principal avait en fait une dépendance sur JUnit, vous devez également spécifier implementationsousdependencies .

J'ai dû spécifier la repositoriessection pour que cela fonctionne, je doute que ce soit le meilleur / le seul moyen.

hoopyfrood
la source