Dereceli çoklu proje test bağımlılıkları


154

Çok projeli bir konfigürasyonum var ve gradle kullanmak istiyorum.

Projelerim şöyle:

  • Proje A

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

    • -> src/main/java(bağlıdır src/main/javaüzerinde Projesi A )
    • -> src/test/java(bağlıdır src/test/javaüzerinde Projesi A )

Benim Projesi B build.gradle dosyası şu şekildedir:

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

Görev compileJavaharika çalışıyor ancak proje A'dakicompileTestJava test dosyasını derlemiyor .


Yanıtlar:


122

Kullanımdan kaldırıldı - Sınıf 5.6 ve üstü için bu yanıtı kullanın .

In Proje B , sadece bir eklemem gerekiyor testCompilebağımlılık:

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

Gradle 1.7 ile test edilmiştir.


7
Classes özelliği kullanımdan kaldırıldı - bunun yerine çıktıyı kullanın.
Fesler

12
SourceSets artık bir projenin genel mülkü olmadığından, Gradle 1.3'te çalışmaz.
David Pärsson

3
Yukarıdaki çözümün gradle testClasses, yapı yapısının gerçekten geçerli olması için en az bir tane gerektirdiğini unutmayın . Eclipse eklentisi, projeyi bundan önce içe aktarmanıza izin vermez. Gerçekten testCompile project(':A')çalışmıyor bir utanç . @ DavidPärsson: Fesler Gradle 1.7 ile test ettiğinden "Gradle 1.3" artık "artık" ile çelişiyor.
Patrick Bergner

3
benim için çalışmadı. Dairesel bağımlılıkla başarısız oldu: compileTestJava \ ---: testClasses \ ---: compileTestJava (*)
rahulmohan

8
Bunu yapma, projelerin başka projelere ulaşması beklenmiyor. Bunun yerine Nikita'nın cevabını kullanın ve bunu proje bağımlılığı olarak doğru bir şekilde modelleyin.
Stefan Oehme

63

Basit bir yol, ProjectB'de açık görev bağımlılığı eklemektir:

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

Zor (ama daha açık) bir yol, ProjectA için ek yapay yapı yapılandırması oluşturmaktır:

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

configurations {
  testArtifacts
}

artifacts {
   testArtifacts myTestsJar
}

ve testCompileProjectB bağımlılığını ekleyin

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

3
Bunu denedim (basit yol) ve bu testClasses oluşturuyor emin olurken, bu CLASSPATH için test yolu eklemez böylece ProjectA test sınıflarına bağlı ProjectB testleri hala oluşturmak için başarısız.
pjz

1
@dmoebius şu şekilde bir testArtifactsyapılandırma eklemeniz gerekir : configurations { testArtifacts } daha fazla ayrıntı için Gradle yardımının bu bölümüne bakın: gradle.org/docs/current/dsl/…
Nikita Skvortsov

7
Gradle 1.8 size isteyebilirsiniz from sourceSets.test.outputve muhtemelen classifier = 'tests'yerine // pack whatever you need...yanıtında
Peter Lamberg

1
Gradle 1.12 ile tam çözümü kullanarak, @PeterLamberg ile eklemelerin beklendiği gibi çalıştığını doğruladı. Projenin Eclipse'e aktarılmasını etkilemez.
sfitts

3
Bu benim için Gradle 4.7'de işe yarıyor. Artık docs.gradle.org/current/dsl/…
Nathan Williams

19

Bu artık Gradle'da birinci sınıf bir özellik olarak destekleniyor. Eklentileri javaveya java-libraryeklentileri olan modüller, java-test-fixturesyardımcı sınıfları ve yardımcı ile tüketilecek kaynakları ortaya çıkaran bir eklenti de içerebilir testFixtures. Bu yaklaşımın eserler ve sınıflandırıcılara karşı faydaları şunlardır:

  • uygun bağımlılık yönetimi (uygulama / api)
  • test kodundan güzel bir şekilde ayırma (ayrı kaynak seti)
  • sadece yardımcı programları ortaya çıkarmak için test sınıflarını filtrelemeye gerek yok
  • Gradle tarafından korunur

Misal

:modul:one

modül / birini / build.gradle

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

modul / tek / src / testFixtures / java / com / example / Helper.java

package com.example;
public class Helper {}

:modul:other

modül / diğer / build.gradle

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

modül / diğer / src / test / Java / com / örnek / diğer / SomeTest.java

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

daha fazla okuma

Daha fazla bilgi için belgelere bakın:
https://docs.gradle.org/current/userguide/java_testing.html#sec:java_test_fixtures

5.6'da eklendi:
https://docs.gradle.org/5.6/release-notes.html#test-fixtures-for-java-projects


Bunu Android'de desteklemek için çalışıyorlar, bkz. İssuetracker.google.com / issues/
Albert Vila Calvo

18

Bu soruna son zamanlarda kendimle karşılaştım ve adam cevap bulmak için zor bir konu.

Yaptığınız hata, bir projenin test öğelerini birincil eserlerini ve bağımlılıklarını dışa aktardığı şekilde dışa aktarması gerektiğini düşünmektir.

Kişisel olarak çok daha başarılı olduğum şey Gradle'da yeni bir proje yapmaktı. Örneğinizde, adını söylerdim

A_Test Projesi -> src / main / java

Şu anda Project A / src / test / java'da bulunan dosyaları src / main / java içine koyacağım. Projenizin testCompile bağımlılıklarını yapın A_Test Project'in derleme bağımlılıklarını yapın.

Sonra Project A_Test'i test B'ye dönüştürün.

Her iki projenin yazarının perspektifinden geldiğinizde mantıklı değil, ancak junit ve scalatest (ve diğerleri) gibi projeleri düşündüğünüzde çok mantıklı olduğunu düşünüyorum. kendi çerçeveleri içinde "test" hedeflerinin bir parçası olarak kabul edilmezler - diğer projelerin test yapılandırmaları içinde kullandıkları birincil yapay nesneler üretir.

Burada listelenen diğer cevapları yapmaya çalışmak benim için kişisel olarak işe yaramadı (Gradle 1.9 kullanarak), ancak burada tarif ettiğim kalıbın daha temiz bir çözüm olduğunu buldum.


Evet, günün sonunda bu yaklaşımı tercih etti.
koma

Bu en iyi yaklaşım! Ancak test kodunu A projesinde tutacağım ve sadece A src / test / java ve B src / test / java için bağımlılıkları A_Test'e taşıyacağım. Ardından A_Test Projesini test edin A ve B'nin uygulama bağımlılığı yapın
Erik

17

Eski bir soru olduğunu biliyorum ama aynı problemi yaşadım ve neler olduğunu anlamak için biraz zaman harcadım. Gradle 1.9 kullanıyorum. Tüm değişiklikler ProjectB'lerde olmalıdırbuild.gradle

ProjectA testlerinde ProjectA test sınıflarını kullanmak için:

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

sourceSetsMülkün ProjectA için kullanılabilir olduğundan emin olmak için:

evaluationDependsOn(':ProjectA')

ProjectB derlerken ProjectA test sınıflarının gerçekten orada olduğundan emin olmak için:

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

1
Bu da benim için işe yaramadı .classesDir.

11

Gradle eklentisi olarak yeni testJar tabanlı (trnsitive bağımlılıklar desteklenir) çözümü:

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

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

Belgelerden

Çok projeli bir gradle derlemeniz varsa, alt projeler arasında test bağımlılıklarınız olabilir (bu muhtemelen projelerinizin iyi yapılandırılmamış olduğuna dair bir ipucudur).

Örneğin, Proje B alt projesinin Proje A'ya bağlı olduğu ve B'nin sadece A'ya derleme bağımlılığı değil, aynı zamanda bir test bağımlılığı olduğu bir projeyi varsayalım. B testlerini derlemek ve çalıştırmak için A'dan bazı test yardımcı sınıflarına ihtiyacımız var.

Varsayılan olarak gradle, bir projenin test oluşturma çıktısından bir kavanoz yapaylığı oluşturmaz.

Bu eklenti, test kaynağı kümesinden bir kavanoz oluşturmak için bir testArchives yapılandırması (testCompile tabanlı) ve bir jarTest görevi ekler (sınıflandırıcı testi kavanozun adına eklenmiştir). Daha sonra B'de A'nın testArchives yapılandırmasına (A'nın geçiş bağımlılıklarını da içerecektir) güvenebiliriz.

A'da build.gradle eklentisini eklerdik:

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

B'de testArchives yapılandırmasına şu şekilde atıf yaparız:

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

1
Bu bağlantı soruyu cevaplayabilse de, cevabın temel kısımlarını buraya eklemek ve bağlantıyı referans olarak sağlamak daha iyidir. Bağlantı verilen sayfa değişirse, yalnızca bağlantı yanıtları geçersiz olabilir. - Şu kaynaktan
Ian

birkaç satır metin eklendi
demon101

Her neyse, yeni gradle eklentisi hakkında bilgi verilmiştir.
demon101

4
@ demon101 Gradle 4.6'da çalışmıyor, hata alıyorumCould not get unknown property 'testClasses' for project ':core' of type org.gradle.api.Project.
Vignesh Sundar

11

Lütfen aşağıdaki güncellemeyi okuyun.

JustACluelessNewbie tarafından açıklanan benzer sorunlar IntelliJ IDEA'da ortaya çıkar. Sorun şu ki bağımlılık testCompile project(':core').sourceSets.test.outputaslında şu anlama gelir: "sınıf oluşturma görevi tarafından oluşturulan sınıflara bağımlı". Dolayısıyla, sınıfların henüz oluşturulmadığı temiz bir proje açarsanız, IDEA bunları tanımaz ve hata bildirir.

Bu sorunu gidermek için derlenmiş sınıflara bağımlılığın yanına sınama kaynak dosyalarına bir bağımlılık eklemeniz gerekir.

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

IDEA tarafından tanınan bağımlılıkları Modül Ayarları -> Bağımlılıklar (test kapsamı) bölümünde gözlemleyebilirsiniz .

Btw. bu hoş bir çözüm değil bu yüzden yeniden düzenleme dikkate değer. Gradle'ın kendisinde yalnızca test destek sınıfları içeren özel bir alt proje vardır. Bkz. Https://docs.gradle.org/current/userguide/test_kit.html

Güncelleme 2016-06-05 daha Ben önerilen çözümü daha az sevdim düşünüyorum. Bununla ilgili birkaç sorun var:

  1. IDEA'da iki bağımlılık yaratır. Biri kaynakları test etmek için diğeri derlenmiş sınıflara işaret eder. Ve bu bağımlılıkların IDEA tarafından hangi sırayla tanınmaları çok önemlidir. Bununla, Modül ayarları -> Bağımlılıklar sekmesinde bağımlılık sırasını değiştirerek oynayabilirsiniz.
  2. Bu bağımlılıkları bildirerek, bağımlılık yapısını gereksiz yere kirletiyorsunuzdur.

Peki daha iyi çözüm nedir? Bence yeni özel kaynak kümesi oluşturuyor ve paylaşılan sınıfları içine alıyor. Aslında Gradle projesinin yazarları bunu testFixtures kaynak kümesi oluşturarak yaptılar.

Bunu yapmak için yapmanız gerekenler:

  1. Kaynak kümesi oluşturun ve gerekli yapılandırmaları ekleyin. Gradle projesinde kullanılan bu komut dosyası eklentisini kontrol edin: https://github.com/gradle/gradle/blob/v4.0.0/gradle/testFixtures.gradle
  2. Bağımlı projede uygun bağımlılığı beyan edin:

    dependencies {
        testCompile project(path: ':module-with-shared-classes', configuration: 'testFixturesUsageCompile')
    }
    
  3. Gradle projesini IDEA'ya aktarın ve içe aktarırken "kaynak kümesi başına ayrı modül oluştur" seçeneğini kullanın.


1
@jannis düzeltildi. Btw. Gradle, Groovy tabanlı test fikstürleri eklentisini Kotlin tabanlı yeni bir ürüne taşıdı: github.com/gradle/gradle/blob/v5.0.0/buildSrc/subprojects/…
Václav Kužel

@ VáclavKužel İlginç çözümünüzü blog yayınınızdan öğreniyorum ve sorunumu çok güzel çözdü. Teşekkürler;)
zaerymoghaddam

10

Fesler'in çözümü benim için işe yaramadı, bir android projesi inşa etmeye çalıştığımda (2.2.0). Bu yüzden elle gerekli sınıfları referans vardı:

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

1
hafif yazım hatası, projeden sonra son alıntıyı kaçırmak (': A'). Bu benim için çalıştı, teşekkürler m8
Ryan Newsom

1
Android için bu fikir benim için hacky hissi olmadan güzel çalıştı stackoverflow.com/a/50869037/197141
arberg

@arberg Evet, iyi bir yaklaşım gibi görünüyor. Gördüğüm tek sınırlama @VisibleForTestingtiftik kurallarında. Bu tür yöntemleri test klasörü altındaki normal modülden çağıramazsınız.
Beloo

5

Partiye çok geç kaldım (şimdi Gradle v4.4) ama bunu bulan herkes için:

varsayarsak:

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

B projesinin (A'dan bazı test sınıflarına ihtiyaç duyan) build.gradle'a gidin ve aşağıdakileri ekleyin:

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

veya (projenize "ProjectB" adı verildiğini varsayarak)

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

İşte bu kadar!


3
Soru Android'den bahsetmiyor. Cevabınızı geliştiricinin Android için geliştirilip geliştirilmediği konusunda agnostik yapabilir misiniz, yoksa yalnızca Android geliştiricileri için mi?
Robin Green

4

Eğer testler arasında paylaşmak gerek sahte bağımlılıkları varsa, yeni bir proje oluşturabilirsiniz projectA-mockve daha sonra test bağımlılık olarak eklemek ProjectAve ProjectB:

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

Bu paylaşım sahte bağımlılıkları açık bir çözümdür, ancak gelen testler gerekiyorsa ProjectAiçinde ProjectBkullanımı diğer çözelti.


Paylaşılan sahte dava için harika bir çözüm!
Erik Sillén

4

Varlık bağımlılıklarını kullanmak istiyorsanız :

  • ProjectB'nin kaynak sınıfları Project A'nın kaynak sınıflarına bağlıdır
  • ProjectB'nin test sınıfları Project A'nın test sınıflarına bağlıdır

sonra build.gradle dosyasındaki ProjectB'nin bağımlılıklar bölümü şöyle görünmelidir:

dependencies {

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

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

}

Bunun çalışması için ProjectA'nın bir test oluşturması gerekiyor kavanozu ve ürettiği eserlere dahil etmesi gerekir.

PROJECTA en build.gradle böyle yapılandırmayı içermelidir:

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

configurations {
    tests
}

artifacts {
    tests testsJar
    archives testsJar
}

jar.finalizedBy(testsJar)

ProjectA'nın eserleri artefaktınıza yayınlandığında bir -testler içerecektir kavanozu .

TestCompile ProjectB bağımlılıkları bölümünde de sınıflarında getirecek -test kavanoz.


Eğer isterseniz includeFlat geliştirme amacıyla ProjectB içinde PROJECTA kaynak ve test sınıfları sonra ProjectB en bölüm bağımlılıkları build.gradle şu şekilde görünecektir:

dependencies {

  compile project(':projecta')

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

}

1
Ne yazık ki (6. Sınıfta), tam olarak istediğim şey olan düz içerme artık çalışmıyor çünkü artık bir yapılandırma 'testi' yok. println(configurations.joinToString("\n") { it.name + " - " + it.allDependencies.joinToString() })(Bir kotlin yapı betiğinde) kullanarak , hangi yapılandırmaların hala var olduğunu ve bağımlılıkları olduğunu belirledim, ancak bu Gradle şikayet etti: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

2

Diğer cevaplardan bazıları şu ya da bu şekilde hatalara neden oldu - Gradle, diğer projelerden test sınıflarını tespit etmedi veya Eclipse projesinin içe aktarıldığında geçersiz bağımlılıkları vardı. Herkes aynı sorunu varsa, ben ile devam öneririz:

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

İlk satır, Tutulmayı diğer projeyi bağımlılık olarak bağlamaya zorlar, böylece tüm kaynaklar dahil edilir ve günceldir. İkincisi, Gradle'ın kaynakları görmesine izin verirken, gibi geçersiz bağımlılık hatalarına neden testCompile project(':core').sourceSets.test.outputolmaz.


2

Burada Kotlin DSL kullanıyorsanız , Gradle'a göre görevinizi böyle oluşturmalısınız belgelerine .

Önceki bazı yanıtlar gibi, test ve ana sınıfları karıştırmamanız için proje içinde test sınıfını paylaşacak özel bir yapılandırma oluşturmanız gerekir.

Basit adımlar

  1. Gelen proje A aşağıdaki konularda eklemek gerekir 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. Sonra bağımlılığınızdaki B projenizde şunları eklemeniz gerekir build.gradle.kts:
dependencies {
    implementation(project(":ProjectA"))
    testImplementation(project(":ProjectA", "test"))
}

-1

B projesinde:

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

1.7-rc-2'de çalışıyor gibi görünüyor


2
Ayrıca, Eclipse tarafından projenin ele alınmasında gereksiz komplikasyonlar yaratır. @NikitaSkvortsov tarafından önerilen çözüm tercih edilir.
14'te
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.