Jak dodać nowy zestaw źródeł do Gradle?

99

Chcę dodać testy integracji do mojej kompilacji Gradle (wersja 1.0). Powinny działać niezależnie od moich normalnych testów, ponieważ wymagają wdrożenia aplikacji internetowej na serwerze lokalnym (testują tę aplikację internetową). Testy powinny móc korzystać z klas zdefiniowanych w moim głównym zestawie źródłowym. Jak to zrobić?

Spina
źródło

Odpowiedzi:

114

Zajęło mi to trochę czasu, a zasoby internetowe nie były świetne. Dlatego chciałem udokumentować moje rozwiązanie.

To jest prosty skrypt budujący gradle, który oprócz głównego i testowego zestawu źródłowego ma ustawione źródło intTest:

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
źródło
7
Nadal będziesz musiał zadeklarować i skonfigurować zadanie testu integracji. Jeśli chodzi o dokumentację, java/withIntegrationTestsw pełnej dystrybucji Gradle znajduje się próbka.
Peter Niederwieser
Dzięki @PeterNiederwieser Poprawiłem mój przykładowy skrypt kompilacji.
Spina
2
Ja też próbowałem to zrobić ... bardzo dziękuję za wysłanie rozwiązania :)
Igor Popov
@PeterNiederwieser Dzięki - czy mógłbyś to połączyć? Uważam również, że ta dokładna sytuacja poważnie brakuje w dokumentach: wszystko jest dobrze i dobrze zdefiniowanie nowego zestawu źródeł, ale nie ma informacji o "podpięciu tego" do rzeczywistego kompilowania, słoika, testu i innych celów - tak jak w tym przykładzie (z wyjątkiem dodawania do słoika lub zrobić nowy słoik z tego zestawu źródłowego).
stolsvik
W linii 6. otrzymuję komunikat „Nie można rozpoznać symbolu 'java'” podczas korzystania z IntelliJ. Jakieś przemyślenia, dlaczego?
Snekse
33

Oto jak to osiągnąłem bez użycia 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
}

Przetestowano przy użyciu: Gradle 1.4 i Gradle 1.6

Mike Rylander
źródło
2
Dzięki za udostępnienie! Dobrze jest zobaczyć alternatywne implementacje.
Spina
1
natomiast java { srcDir 'src/integrationtest/java' } resources { srcDir 'src/integrationtest/resources' }nie jest istotne, ponieważ to właśnie redeclares src/<sourceSetName>/...do src/integrationtest/...: tu: zmiana T kapitał do niższej t
childno͡.de
Uważaj na takie podejście. compileClasspath += sourceSets.main.runtimeClasspathłączy dwa zestawy plików. Nie ma zwykłego rozwiązywania konfliktów dla zależności. Możesz otrzymać dwie wersje tej samej biblioteki. Pomoże w tym rozszerzenie konfiguracji.
chalimartines
20

Zostało to kiedyś napisane dla Gradle 2.x / 3.x w 2016 roku i jest bardzo przestarzałe !! Proszę spojrzeć na udokumentowane rozwiązania w Gradle 4 i nowszych


Podsumowując obie stare odpowiedzi (uzyskaj najlepszą i minimalną wykonalność obu światów):

najpierw kilka ciepłych słów:

  1. najpierw musimy zdefiniować sourceSet:

    sourceSets {
        integrationTest
    }
  2. następnie rozwijamy sourceSetfrom test, dlatego używamy test.runtimeClasspath(który zawiera wszystkie zależności od samego testAND test) jako ścieżki klas dla wyprowadzonych sourceSet:

    sourceSets {
        integrationTest {
            compileClasspath += sourceSets.test.runtimeClasspath
            runtimeClasspath += sourceSets.test.runtimeClasspath // ***)
        }
    }
    • uwaga ) w jakiś sposób ta ponowna deklaracja / rozszerzenie dla sourceSets.integrationTest.runtimeClasspathjest potrzebna, ale powinna być nieistotna, ponieważ runtimeClasspathzawsze się rozwija output + runtimeSourceSet, nie otrzymuj tego
  3. definiujemy dedykowane zadanie do przeprowadzenia samych testów integracyjnych:

    task integrationTest(type: Test) {
    }
  4. Skonfiguruj integrationTestklasy testowe i ścieżki klas. Wartości domyślne z javawtyczki używają rozszerzeniatest sourceSet

    task integrationTest(type: Test) {
        testClassesDir = sourceSets.integrationTest.output.classesDir
        classpath = sourceSets.integrationTest.runtimeClasspath
    }
  5. (opcjonalnie) automatyczne uruchamianie po teście

    integracjaTest.dependsOn test
    

  6. (opcjonalnie) dodaj zależność od check(więc zawsze działa, gdy buildlub checksą wykonywane)

    tasks.check.dependsOn(tasks.integrationTest)
  7. (opcjonalnie) dodaj java, zasoby do sourceSetobsługi automatycznego wykrywania i utwórz te „częściowe” w swoim IDE. tzn. IntelliJ IDEA automatycznie utworzy sourceSetkatalogi java i zasoby dla każdego zestawu, jeśli nie istnieje:

    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)

odwołujący się do:

Niestety, przykładowy kod na github.com/gradle/gradle/subprojects/docs/src/samples/java/customizedLayout/build.gradle lub … / gradle /… / withIntegrationTests / build.gradle wydaje się nie obsługiwać tego lub ma inny / bardziej złożone / dla mnie i tak nie ma jaśniejszego rozwiązania!

childno͡.de
źródło
1
(!) jak się okazuje, jednorazowe użycie rozszerzeń sourceSet bez konfiguracji lub danych wyjściowych skutkuje błędem pomysłu po początkowym otwarciu projektu. zależność kompilacji (tutaj: test) dla nowego "modułu" (tutaj: IntegracjaTest) nie jest dostępna po raz pierwszycompileTestJava
childno͡.de
2
classesDirzostał przeniesiony classesDirsna gradle 5
deFreitas
dzięki za podpowiedź @deFreitas, oznaczyłem odpowiedź jako nieaktualną
childno͡.de
9

Mgławica-aspekt wtyczki eliminuje boilerplate:

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

W szczególności w przypadku testów integracyjnych, nawet jeśli jest to zrobione za Ciebie , po prostu zastosuj:

apply plugin: 'nebula.integtest'

Linki do portalu wtyczek Gradle dla każdego z nich to:

  1. nebula.facet
  2. nebula.integtest
jkschneider
źródło
7

Jeśli używasz

Aby IntelliJ rozpoznał niestandardowy zestaw źródeł jako root źródeł testowych:

plugin {
    idea
}

idea {
    module {
        testSourceDirs = testSourceDirs + sourceSets["intTest"].allJava.srcDirs
        testResourceDirs = testResourceDirs + sourceSets["intTest"].resources.srcDirs
    }
}
jenglert
źródło
2

Oto, co działa dla mnie od wersji 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
}

Począwszy od wersji 4.0, Gradle używa teraz oddzielnych katalogów klas dla każdego języka w zestawie źródłowym. Jeśli więc Twój skrypt kompilacji używa sourceSets.integrationTest.output.classesDir, zobaczysz następujące ostrzeżenie o wycofaniu.

Gradle używa teraz osobnych katalogów wyjściowych dla każdego języka JVM, ale ta kompilacja zakłada jeden katalog dla wszystkich klas ze zbioru źródłowego. To zachowanie zostało wycofane i jest zaplanowane do usunięcia w Gradle 5.0

Aby pozbyć się tego ostrzeżenia, po prostu przełącz się na sourceSets.integrationTest.output.classesDirs. Aby uzyskać więcej informacji, zobacz informacje o wersji Gradle 4.0 .

Ryan Sobol
źródło
przełączyć się na <hmm> ?? Twoje przed i po są takie same.
Merk
-1

Jestem nowy w Gradle, używam Gradle 6.0.1 JUnit 4.12. Oto, co wymyśliłem, aby rozwiązać ten problem.

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

dependencies {
    testImplementation 'junit:junit:4.12'
}

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

Zauważ, że główne źródło i źródło testowe są przywoływane osobno, jedno poniżej maini jedno poniżejtest .

testImplementationPod poz dependenciessłuży tylko za zebranie źródło w test. Jeśli twój główny kod faktycznie miał zależność od JUnit, możesz również określić implementationponiżejdependencies .

Musiałem określić repositoriessekcję, aby to zadziałało, wątpię, czy jest to najlepszy / jedyny sposób.

hoopyfrood
źródło