Dipendenze di test multiprogetto con pendenza


154

Ho una configurazione multi-progetto e voglio usare Gradle.

I miei progetti sono così:

  • Progetto A

    • -> src/main/java
    • -> src/test/java
  • Progetto B

    • -> src/main/java(dipende src/main/javadal Progetto A )
    • -> src/test/java(dipende src/test/javadal Progetto A )

Il mio file Project B build.gradle è così:

apply plugin: 'java'
dependencies {
  compile project(':ProjectA')
}

Il compito compileJavagrande opera, ma il compileTestJavanon compilare il file di test da Progetto A .


Risposte:


122

Obsoleto: per Gradle 5.6 e versioni successive usa questa risposta .

Nel Progetto B , devi solo aggiungere una testCompiledipendenza:

dependencies {
  ...
  testCompile project(':A').sourceSets.test.output
}

Testato con Grado 1.7.


7
Viene fuori che la proprietà class è deprecata - usa invece l'output.
Fesler,

12
Questo non funziona in Gradle 1.3 poiché sourceSets non è più una proprietà pubblica di un progetto.
David Pärsson,

3
Tieni presente che la soluzione di cui sopra richiede almeno un periodo gradle testClassesprima che la struttura di compilazione sia effettivamente valida. Ad esempio il plugin Eclipse non ti permetterà di importare il progetto prima di quello. È davvero un peccato testCompile project(':A')non funziona. @ DavidPärsson: "Gradle 1.3" contraddice "non più" da quando Fesler ha testato con Gradle 1.7.
Patrick Bergner,

3
non ha funzionato per me. Errore con dipendenza circolare: compileTestJava \ ---: testClasses \ ---: compileTestJava (*)
rahulmohan,

8
Non farlo, i progetti non dovrebbero entrare in altri progetti. Usa invece la risposta di Nikita, modellandola correttamente come dipendenza del progetto.
Stefan Oehme,

63

Il modo semplice è aggiungere la dipendenza esplicita dell'attività in ProjectB:

compileTestJava.dependsOn tasks.getByPath(':ProjectA:testClasses')

Il modo più difficile (ma più chiaro) è creare una configurazione artefatto aggiuntiva per ProjectA:

task myTestsJar(type: Jar) { 
  // pack whatever you need...
}

configurations {
  testArtifacts
}

artifacts {
   testArtifacts myTestsJar
}

e aggiungi la testCompiledipendenza per ProjectB

apply plugin: 'java'
dependencies {
  compile project(':ProjectA')
  testCompile project(path: ':ProjectA', configuration: 'testArtifacts')
}

3
Ho provato questo (in modo semplice) e mentre questo si assicura che costruisca testClasses, non aggiunge il percorso di test a CLASSPATH, quindi i miei test ProjectB che dipendono dalle classi di test ProjectA non riescono ancora a essere compilati.
pjz,

1
@dmoebius devi aggiungere una testArtifactsconfigurazione come questa: configurations { testArtifacts } per maggiori dettagli consulta questa sezione della guida di Gradle: gradle.org/docs/current/dsl/…
Nikita Skvortsov,

7
Nel Grado 1.8 potresti desiderare from sourceSets.test.outpute possibilmente classifier = 'tests'al posto della // pack whatever you need...risposta
Peter Lamberg,

1
Confermato che con Gradle 1.12 utilizzando la soluzione completa, con @PeterLamberg le aggiunte suggerite funzionano come previsto. Non influisce sull'importazione del progetto in Eclipse.
sfitts

3
Questo funziona per me nel Gradle 4.7. Ora hanno alcuni documenti sull'approccio a docs.gradle.org/current/dsl/…
Nathan Williams,

19

Questo è ora supportato come funzionalità di prima classe in Gradle. Moduli conjava o java-libraryplug-in possono anche includere un java-test-fixturesplug-in che espone le classi e le risorse di testFixturessupporto da utilizzare con l' helper. I vantaggi di questo approccio contro artefatti e classificatori sono:

  • corretta gestione delle dipendenze (implementazione / api)
  • bella separazione dal codice di test (set di sorgenti separato)
  • non è necessario filtrare le classi di test per esporre solo i programmi di utilità
  • gestito da Gradle

Esempio

:modul:one

Modul / un / build.gradle

plugins {
  id "java-library" // or "java"
  id "java-test-fixtures"
}

Modul / un / src / testFixtures / java / com / es / Helper.java

package com.example;
public class Helper {}

:modul:other

Modul / altro / build.gradle

plugins {
  id "java" // or "java-library"
}
dependencies {
  testImplementation(testFixtures(project(":modul:one")))
}

Modul / altro / src / test / java / com / es / altro / SomeTest.java

package com.example.other;
import com.example.Helper;
public class SomeTest {
  @Test void f() {
    new Helper(); // used from :modul:one's testFixtures
  }
}

Ulteriori letture

Per ulteriori informazioni, consultare la documentazione:
https://docs.gradle.org/current/userguide/java_testing.html#sec:java_test_fixtures

È stato aggiunto in 5.6:
https://docs.gradle.org/5.6/release-notes.html#test-fixtures-for-java-projects



18

Mi sono imbattuto in questo problema di recente, e l'uomo è un problema difficile da trovare risposte.

L'errore che stai facendo è pensare che un progetto dovrebbe esportare i suoi elementi di test nello stesso modo in cui esporta i suoi artefatti e dipendenze primari.

Quello che ho avuto molto più successo con personalmente è stato realizzare un nuovo progetto in Gradle. Nel tuo esempio, lo nominerei

Progetto A_Test -> src / main / java

Vorrei inserire in src / main / java i file che hai attualmente nel Progetto A / src / test / java. Effettua qualsiasi test Compilare le dipendenze del tuo Progetto A compilare le dipendenze del Progetto A_Test.

Quindi rendere Project A_Test un testCompilare la dipendenza del Progetto B.

Non è logico quando ci si arriva dal punto di vista dell'autore di entrambi i progetti, ma penso che abbia molto senso pensare a progetti come junit e scalatest (e altri. Anche se quei framework sono correlati ai test, essi non sono considerati parte degli obiettivi di "test" all'interno dei propri framework: producono artefatti primari che altri progetti utilizzano solo nella loro configurazione di test. Volete solo seguire lo stesso schema.

Cercare di fare le altre risposte elencate qui non ha funzionato per me personalmente (usando Gradle 1.9), ma ho scoperto che lo schema che descrivo qui è comunque una soluzione più pulita.


Sì, ho optato per questo approccio alla fine della giornata.
Koma,

Questo è l'approccio migliore! Tranne che terrei il codice di test nel progetto A e sposterò solo le dipendenze sia per A src / test / java che per B src / test / java in A_Test. Quindi fai del progetto A_Test una prova. Dipendenza dall'implementazione di A e B.
Erik Sillén,

17

So che è una vecchia domanda, ma ho avuto lo stesso problema e ho trascorso un po 'di tempo a capire cosa stesse succedendo. Sto usando Gradle 1.9. Tutte le modifiche dovrebbero essere in ProjectBbuild.gradle

Per utilizzare le classi di test da ProjectA nei test di ProjectB:

testCompile files(project(':ProjectA').sourceSets.test.output.classesDir)

Per assicurarsi che la sourceSetsproprietà sia disponibile per ProjectA:

evaluationDependsOn(':ProjectA')

Per assicurarsi che le classi di test da ProjectA siano effettivamente presenti, quando si compila ProjectB:

compileTestJava.dependsOn tasks.getByPath(':ProjectA:testClasses')

1
Questo ha funzionato anche per me, tranne che ho dovuto omettere il .classesDir.

11

Nuova soluzione basata su testJar (dipendenze trnsitive supportate) disponibile come plugin gradle:

https://github.com/hauner/gradle-plugins/tree/master/jartest

https://plugins.gradle.org/plugin/com.github.hauner.jarTest/1.0

Dalla documentazione

Nel caso in cui si disponga di una build a più progetti, è possibile che si verifichino dipendenze di test tra sottoprogetti (il che probabilmente suggerisce che i progetti non sono ben strutturati).

Ad esempio, supponiamo che un progetto in cui il sottoprogetto Progetto B dipenda dal Progetto A e B non abbia solo una dipendenza di compilazione da A, ma anche una dipendenza di test. Per compilare ed eseguire i test di B sono necessarie alcune classi di helper di test di A.

Per impostazione predefinita, il gradle non crea un artefatto jar dall'output della build di test di un progetto.

Questo plugin aggiunge una configurazione testArchives (basata su testCompile) e un'attività jarTest per creare un jar dal set di sorgenti di test (con il test classificatore aggiunto al nome del jar). Possiamo quindi dipendere in B dalla configurazione testArchives di A (che includerà anche le dipendenze transitive di A).

In A aggiungeremo il plugin a build.gradle:

apply plugin: 'com.github.hauner.jarTest'

In B facciamo riferimento alla configurazione testArchives in questo modo:

dependencies {
    ...
    testCompile project (path: ':ProjectA', configuration: 'testArchives') 
}

1
Sebbene questo collegamento possa rispondere alla domanda, è meglio includere qui le parti essenziali della risposta e fornire il collegamento come riferimento. Le risposte di solo collegamento possono diventare non valide se la pagina collegata cambia. - Dalla recensione
Ian,

sono state aggiunte poche righe di testo
demon101

Ad ogni modo, sono state fornite informazioni sul nuovo plugin gradle.
demon101,

4
@ demon101 Non funziona in Gradle 4.6, ricevendo erroreCould not get unknown property 'testClasses' for project ':core' of type org.gradle.api.Project.
Vignesh Sundaramoorthy,

11

Si prega di leggere il seguente aggiornamento.

Problemi simili descritti da JustACluelessNewbie si verificano in IntelliJ IDEA. Il problema è quella dipendenzatestCompile project(':core').sourceSets.test.output realtà significa: "dipende dalle classi generate dall'attività di costruzione gradle". Quindi, se apri un progetto pulito in cui le classi non sono ancora generate, IDEA non le riconoscerà e segnalerà un errore.

Per risolvere questo problema è necessario aggiungere una dipendenza dai file di origine del test accanto alla dipendenza dalle classi compilate.

// First dependency is for IDEA
testCompileOnly files { project(':core').sourceSets.test.java.srcDirs }
// Second is for Gradle
testCompile project(':core').sourceSets.test.output

È possibile osservare le dipendenze riconosciute da IDEA in Impostazioni modulo -> Dipendenze (ambito test) .

Btw. questa non è una buona soluzione, quindi vale la pena considerare il refactoring. Gradle stesso ha sottoprogetto speciale contenente solo classi di supporto al test. Vedi https://docs.gradle.org/current/userguide/test_kit.html

Aggiornamento 2016-06-05 Di più Sto pensando alla soluzione proposta meno mi piace. Ci sono alcuni problemi con esso:

  1. Crea due dipendenze in IDEA. Un punto per testare le fonti un altro per le classi compilate. Ed è fondamentale in quale ordine queste dipendenze sono riconosciute dall'IDEA. Puoi giocarci cambiando l'ordine delle dipendenze in Impostazioni modulo -> scheda Dipendenze.
  2. Dichiarando queste dipendenze si inquina inutilmente la struttura delle dipendenze.

Quindi qual è la soluzione migliore? Secondo me, sta creando un nuovo set di sorgenti personalizzato e inserendo classi condivise. In realtà gli autori del progetto Gradle lo hanno fatto creando il set di sorgenti di testFixtures.

Per farlo devi solo:

  1. Crea set di sorgenti e aggiungi le configurazioni necessarie. Controlla questo plugin di script utilizzato nel progetto Gradle: https://github.com/gradle/gradle/blob/v4.0.0/gradle/testFixtures.gradle
  2. Dichiarare la dipendenza corretta nel progetto dipendente:

    dependencies {
        testCompile project(path: ':module-with-shared-classes', configuration: 'testFixturesUsageCompile')
    }
    
  3. Importa il progetto Gradle in IDEA e usa l'opzione "crea modulo separato per set di sorgenti" durante l'importazione.


1
@jannis fixed. Btw. Gradle ha spostato il suo plug-in di test Groovy sul nuovo Kotlin: github.com/gradle/gradle/blob/v5.0.0/buildSrc/subprojects/…
Václav Kužel

@ VáclavKužel Ho scoperto la tua soluzione interessante tramite il tuo post sul blog e ho risolto molto bene il mio problema. Grazie;)
zaerymoghaddam,

10

La soluzione di Fesler non ha funzionato per me, quando ho provato a costruire un progetto Android (grado 2.2.0). Quindi ho dovuto fare riferimento manualmente alle classi richieste:

android {
    sourceSets {
        androidTest {
            java.srcDir project(':A').file("src/androidTest/java")
        }
        test {
            java.srcDir project(':A').file("src/test/java")
        }
    }
}

1
piccolo errore di battitura, manca la citazione finale dopo il progetto (': A'). Questo ha funzionato per me, grazie m8
Ryan Newsom il

1
Per Android questa idea ha funzionato benissimo per me, senza la sensazione hacky stackoverflow.com/a/50869037/197141
Arberg

@arberg Sì, sembra un buon approccio. L'unica limitazione che vedo è con le @VisibleForTestingregole di lanugine. Non sarai in grado di chiamare tali metodi dal modulo normale nella cartella non test.
Beloo

5

Sono così in ritardo alla festa (ora è Gradle v4.4) ma per chiunque lo trovi:

assumendo:

~/allProjects
|
|-/ProjectA/module-a/src/test/java
|
|-/ProjectB/module-b/src/test/java

Vai al build.gradle del progetto B (quello che richiede alcune classi di test da A) e aggiungi quanto segue:

sourceSets {
    String sharedTestDir = "${projectDir}"+'/module-b/src/test/java'
    test {
        java.srcDir sharedTestDir
    }
}

o (supponendo che il tuo progetto sia chiamato "ProjectB")

sourceSets {
    String sharedTestDir = project(':ProjectB').file("module-b/src/test/java")
    test {
        java.srcDir sharedTestDir
    }
}

Ecco!


3
La domanda non menziona Android. Puoi rendere la tua risposta agnostica al fatto che lo sviluppatore stia sviluppando per Android o no, oppure è solo per gli sviluppatori Android?
Robin Green,

4

Se si dispone di dipendenze simulate che è necessario condividere tra i test, è possibile creare un nuovo progetto projectA-mocke quindi aggiungerlo come dipendenza del test a ProjectAe ProjectB:

dependencies {
  testCompile project(':projectA-mock')
}

Questa è una soluzione chiara per condividere finte dipendenze, ma se è necessario eseguire test dall'altra soluzione ProjectAin ProjectBuso.


Ottima soluzione per il caso simulato condiviso!
Erik Sillén,

4

Se si desidera utilizzare dipendenze artefatto per avere:

  • Le classi di origine del progetto B dipendono dalle classi di origine del progetto A.
  • Le classi di test di ProjectB dipendono dalle classi di test di Project A.

la sezione delle dipendenze di ProjectB in build.gradle dovrebbe assomigliare a questa:

dependencies {

  compile("com.example:projecta:1.0.0")

  testCompile("com.example:projecta:1.0.0:tests")

}

Perché questo funzioni ProjectA deve creare un test vaso e includerlo nei manufatti che produce.

Build.gradle di ProjectA dovrebbe contenere una configurazione come questa:

task testsJar(type: Jar, dependsOn: testClasses) {
    classifier = 'tests'
    from sourceSets.test.output
}

configurations {
    tests
}

artifacts {
    tests testsJar
    archives testsJar
}

jar.finalizedBy(testsJar)

Quando i manufatti di ProjectA vengono pubblicati sul tuo manufatto includeranno un vaso -test .

Il testCompile nella sezione delle dipendenze di ProjectB inserirà le classi nel vaso -tests .


Se si desidera includere le origini sorgente e di test di ProjectA Flat in ProjectB per scopi di sviluppo, la sezione delle dipendenze in build.gradle di ProjectB dovrebbe apparire così:

dependencies {

  compile project(':projecta')

  testCompile project(path: ':projecta', configuration: 'tests')

}

1
Sfortunatamente (nel Grado 6) l'appartamento include, che era esattamente quello che volevo, non funziona più perché non ci sono più "test" di configurazione. Usando println(configurations.joinToString("\n") { it.name + " - " + it.allDependencies.joinToString() })(in un buildscript di kotlin), ho determinato quali configurazioni esistono ancora e hanno dipendenze, ma per tutti questi Gradle si è lamentato:Selected configuration 'testCompileClasspath' on 'project :sdk' but it can't be used as a project dependency because it isn't intended for consumption by other components.
Xerus il

2

Alcune delle altre risposte hanno causato errori in un modo o nell'altro: Gradle non ha rilevato classi di test da altri progetti o il progetto Eclipse ha avuto dipendenze non valide durante l'importazione. Se qualcuno ha lo stesso problema, suggerisco di andare con:

testCompile project(':core')
testCompile files(project(':core').sourceSets.test.output.classesDir)

La prima riga obbliga Eclipse a collegare l'altro progetto come dipendenza, quindi tutte le fonti sono incluse e aggiornate. Il secondo consente a Gradle di vedere effettivamente le fonti, senza causare errori di dipendenza non validi come testCompile project(':core').sourceSets.test.outputfa.


2

Qui se si utilizza Kotlin DSL , è necessario creare un'attività simile in base alla documentazione di Gradle .

Come una risposta precedente, è necessario creare una configurazione speciale all'interno del progetto che condividerà la sua classe test, in modo da non mescolare test e classi principali.

Semplici passaggi

  1. Nel progetto A dovresti aggiungere build.gradle.kts:
configurations {
    create("test")
}

tasks.register<Jar>("testArchive") {
    archiveBaseName.set("ProjectA-test")
    from(project.the<SourceSetContainer>()["test"].output)
}

artifacts {
    add("test", tasks["testArchive"])
}
  1. Quindi nel tuo progetto B nelle dipendenze, dovrai aggiungere build.gradle.kts:
dependencies {
    implementation(project(":ProjectA"))
    testImplementation(project(":ProjectA", "test"))
}

-1

nel progetto B:

dependencies {
  testCompile project(':projectA').sourceSets.test.output
}

Sembra funzionare in 1.7-rc-2


2
Inoltre, crea complicazioni inutili nella gestione del progetto da parte di Eclipse. È preferibile la soluzione suggerita da @NikitaSkvortsov.
sfitts
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.