Wie füge ich Gradle ein neues Quellenset hinzu?

99

Ich möchte meinem Gradle-Build (Version 1.0) Integrationstests hinzufügen. Sie sollten getrennt von meinen normalen Tests ausgeführt werden, da eine Webanwendung für localhost bereitgestellt werden muss (sie testen diese Webanwendung). Die Tests sollten in der Lage sein, Klassen zu verwenden, die in meinem Hauptquellensatz definiert sind. Wie mache ich das möglich?

Spina
quelle

Antworten:

114

Ich habe eine Weile gebraucht, um das herauszufinden, und die Online-Ressourcen waren nicht großartig. Also wollte ich meine Lösung dokumentieren.

Dies ist ein einfaches Gradle-Build-Skript, das zusätzlich zu den Haupt- und Testquellensätzen einen intTest-Quellensatz enthält:

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
quelle
7
Sie müssen noch eine Integrationstestaufgabe deklarieren und konfigurieren. In Bezug auf die Dokumentation gibt es ein java/withIntegrationTestsBeispiel in der vollständigen Gradle-Verteilung.
Peter Niederwieser
Danke @PeterNiederwieser Ich habe mein Beispiel-Build-Skript korrigiert.
Spina
2
Ich habe auch versucht, dies zu tun ... vielen Dank für die Veröffentlichung der Lösung :)
Igor Popov
@PeterNiederwieser Danke - könntest du es bitte verlinken? Ich finde auch, dass genau diese Situation in den Dokumenten stark fehlt: Es ist alles gut und schön, ein neues sourceSet zu definieren, aber keine Informationen darüber, wie man dies in das eigentliche Kompilieren, JAR, Test und so weiter einbindet - wie in diesem Beispiel (außer zum Hinzufügen) in das Glas oder machen ein neues Glas aus diesem sourceSet).
Stolsvik
In Zeile 6 wird bei Verwendung von IntelliJ "Symbol 'Java' kann nicht aufgelöst werden" angezeigt. Irgendwelche Gedanken darüber warum?
Snekse
33

Hier ist, wie ich dies ohne Verwendung erreicht habe 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
}

Getestet mit: Gradle 1.4 und Gradle 1.6

Mike Rylander
quelle
2
Danke für das Teilen! Es ist gut, alternative Implementierungen zu sehen.
Spina
1
während java { srcDir 'src/integrationtest/java' } resources { srcDir 'src/integrationtest/resources' }da es nicht relevant ist nur redeclares src/<sourceSetName>/...zu src/integrationtest/...: hier: die Hauptstadt T auf einen niedrigeren t ändern
childno͡.de
Hüten Sie sich vor diesem Ansatz. compileClasspath += sourceSets.main.runtimeClasspathkombiniert zwei Sätze von Dateien. Es gibt keine übliche Konfliktlösung für Abhängigkeiten. Sie können mit zwei Versionen derselben Bibliothek enden. Das Erweitern von Konfigurationen hilft dabei.
Chalimartines
20

Dies wurde einmal für Gradle 2.x / 3.x im Jahr 2016 geschrieben und ist weit veraltet !! Bitte schauen Sie sich die dokumentierten Lösungen in Gradle 4 und höher an


Um beide alten Antworten zusammenzufassen (beste und minimale Lebensfähigkeit beider Welten):

zuerst ein paar warme worte:

  1. Zuerst müssen wir Folgendes definieren sourceSet:

    sourceSets {
        integrationTest
    }
  2. Als nächstes erweitern wir das sourceSetfrom test, daher verwenden wir das test.runtimeClasspath(das alle Abhängigkeiten von testAND testselbst enthält) als Klassenpfad für das abgeleitete sourceSet:

    sourceSets {
        integrationTest {
            compileClasspath += sourceSets.test.runtimeClasspath
            runtimeClasspath += sourceSets.test.runtimeClasspath // ***)
        }
    }
    • note ) irgendwie wird diese erneute Erklärung / Erweiterung sourceSets.integrationTest.runtimeClasspathbenötigt, sollte aber irrelevant sein, da sie runtimeClasspathimmer erweitert wird output + runtimeSourceSet, verstehe sie nicht
  3. Wir definieren eine spezielle Aufgabe, um nur Integrationstests auszuführen:

    task integrationTest(type: Test) {
    }
  4. Konfigurieren Sie die integrationTestverwendeten Testklassen und Klassenpfade. Die Standardeinstellungen des javaPlugins verwenden dietest sourceSet

    task integrationTest(type: Test) {
        testClassesDir = sourceSets.integrationTest.output.classesDir
        classpath = sourceSets.integrationTest.runtimeClasspath
    }
  5. (optional) Nach dem Test automatisch ausführen

    IntegrationTest.dependsOn Test
    

  6. (optional) Abhängigkeit hinzufügen von check(damit es immer ausgeführt wird, wenn buildoder checkausgeführt wird)

    tasks.check.dependsOn(tasks.integrationTest)
  7. (optional) Fügen Sie Java hinzu, um die sourceSetautomatische Erkennung zu unterstützen, und erstellen Sie diese "Partials" in Ihrer IDE. dh IntelliJ IDEA erstellt automatisch sourceSetVerzeichnisse Java und Ressourcen für jeden Satz, wenn es nicht existiert:

    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)

in Bezug auf:

Leider scheint der Beispielcode auf github.com/gradle/gradle/subprojects/docs/src/samples/java/customizedLayout/build.gradle oder … / gradle /… / withIntegrationTests / build.gradle dies nicht zu handhaben oder hat einen anderen / komplexer / für mich sowieso keine klarere Lösung!

childno͡.de
quelle
1
(!) Wie sich herausstellt, führt die einmalige Verwendung von sourceSet-Erweiterungen ohne Konfigurationen oder Ausgabe nach dem ersten Öffnen eines Projekts zu einem Fehler in der Idee. Die Build-Abhängigkeit (hier: Test) für das neue "Modul" (hier: IntegrationTest) ist beim ersten compileTestJava
Mal
2
classesDirwurde classesDirsauf Gradle 5
deFreitas
danke für den hinweis @deFreitas, ich habe die
antwort
9

Das Nebula-Facetten- Plugin eliminiert die Boilerplate:

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

Für Integrationstests, auch wenn dies für Sie erledigt wird , wenden Sie einfach Folgendes an:

apply plugin: 'nebula.integtest'

Die Links zum Gradle-Plugin-Portal für jedes sind:

  1. nebula.facet
  2. nebula.integtest
jkschneider
quelle
7

Wenn Sie verwenden

So erhalten Sie, dass IntelliJ ein benutzerdefiniertes Quellenset als Testquellenstamm erkennt:

plugin {
    idea
}

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

Folgendes funktioniert für mich ab 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
}

Ab Version 4.0 verwendet Gradle jetzt separate Klassenverzeichnisse für jede Sprache in einem Quellensatz. Wenn Ihr Build-Skript also verwendet sourceSets.integrationTest.output.classesDir, wird die folgende Warnung zur Ablehnung angezeigt.

Gradle verwendet jetzt separate Ausgabeverzeichnisse für jede JVM-Sprache. Bei diesem Build wird jedoch ein einziges Verzeichnis für alle Klassen aus einem Quellensatz angenommen. Dieses Verhalten ist veraltet und soll in Gradle 5.0 entfernt werden

Um diese Warnung zu entfernen, wechseln Sie sourceSets.integrationTest.output.classesDirsstattdessen zu. Weitere Informationen finden Sie in den Versionshinweisen zu Gradle 4.0 .

Ryan Sobol
quelle
auf <hmm> umschalten ?? Dein Vorher und Nachher sind gleich.
Merk
0

Ich bin neu in Gradle und verwende Gradle 6.0.1 JUnit 4.12. Folgendes habe ich mir ausgedacht, um dieses Problem zu lösen.

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

dependencies {
    testImplementation 'junit:junit:4.12'
}

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

Beachten Sie, dass auf die Hauptquelle und die Testquelle separat verwiesen wird, eine unter mainund eine unter test.

Das testImplementationElement unter dependencieswird nur zum Kompilieren der Quelle in verwendet test. Wenn Ihr Hauptcode tatsächlich eine Abhängigkeit von JUnit hätte, würden Sie auch implementationunter angebendependencies .

Ich musste den repositoriesAbschnitt angeben , damit dies funktioniert. Ich bezweifle, dass dies der beste / einzige Weg ist.

hoopyfrood
quelle