Gradleを使用したマルチプロジェクトテストの依存関係


153

マルチプロジェクト構成があり、gradleを使用したいと思います。

私のプロジェクトは次のとおりです:

  • プロジェクトA

    • -> src/main/java
    • -> src/test/java
  • プロジェクトB

    • - > src/main/java(依存src/main/javaプロジェクトA
    • - > src/test/java(依存src/test/javaプロジェクトA

私のプロジェクトB build.gradleファイルは次のとおりです。

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

タスクcompileJavacompileTestJavaうまく機能しますが、プロジェクトAからのテストファイルはコンパイルされません。


回答:


122

非推奨-Gradle 5.6以降では、この回答を使用してください

では、プロジェクトB、あなただけ追加する必要があるtestCompile依存関係を:

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

Gradle 1.7でテスト済み。


7
クラスプロパティが非推奨であることが判明-代わりに出力を使用してください。
Fesler

12
sourceSetsはプロジェクトのパブリックプロパティではなくなったため、これはGradle 1.3では機能しません。
DavidPärsson2013年

3
上記のソリューションではgradle testClasses、ビルド構造が実際に有効になる前に少なくともaが必要であることを覚えておいてください。たとえば、Eclipseプラグインでは、その前にプロジェクトをインポートできません。本当に残念testCompile project(':A')です。@DavidPärsson:FeslerがGradle 1.7でテストしたため、「Gradle 1.3」は「もはや」と矛盾します。
Patrick Bergner、2014年

3
うまくいきませんでした。循環依存で失敗しました:compileTestJava \ ---:testClasses \ ---:compileTestJava(*)
rahulmohan

8
これを行わないでください。プロジェクトが他のプロジェクトに到達することは想定されていません。代わりにNikitaの回答を使用して、これをプロジェクトの依存関係として正しくモデル化してください。
Stefan Oehme 2017

63

簡単な方法は、ProjectBに明示的なタスクの依存関係を追加することです。

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

難しい(しかしより明確な)方法は、ProjectAに追加のアーティファクト構成を作成することです。

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

configurations {
  testArtifacts
}

artifacts {
   testArtifacts myTestsJar
}

testCompileProjectB の依存関係を追加します

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

3
私はこれを試しました(簡単な方法)。これにより、testClassesがビルドされることが確認されますが、CLASSPATHにテストパスが追加されないため、ProjectAテストクラスに依存する私のProjectBテストは引き続きビルドできません。
pjz

1
@dmoebius testArtifactsこのように構成を追加する必要があります。configurations { testArtifacts } 詳細については、Gradleヘルプのこのセクションを参照してください:gradle.org/docs/current/dsl/…–
Nikita Skvortsov

7
Gradle 1.8 では、答えの代わりにしたいfrom sourceSets.test.output場合がありますclassifier = 'tests'// pack whatever you need...
Peter Lamberg

1
Gradle 1.12で完全なソリューションを使用し、@ PeterLambergで追加が期待どおりに機能することを提案したことを確認しました。プロジェクトのEclipseへのインポートには影響しません。
2014年

3
これはGradle 4.7では機能します。彼らは今でアプローチに関するいくつかのドキュメントを持っているdocs.gradle.org/current/dsl/...
ネイサン・ウィリアムス

19

これは、Gradleのファーストクラス機能としてサポートされるようになりました。javaまたはjava-libraryプラグインを持つモジュールには、java-test-fixturesヘルパーで使用されるヘルパークラスとリソースを公開するプラグインを含めることもできますtestFixtures。アーティファクトと分類子に対するこのアプローチの利点は次のとおりです。

  • 適切な依存関係管理(実装/ API)
  • テストコードからの適切な分離(別のソースセット)
  • ユーティリティのみを公開するためにテストクラスを除外する必要はありません
  • Gradleが管理

:modul:one

modul / one / build.gradle

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

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

package com.example;
public class Helper {}

:modul:other

modul / other / build.gradle

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

modul / other / src / test / java / com / example / other / SomeTest.java

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

参考文献

詳細については、ドキュメントを参照してくださいhttps : //docs.gradle.org/current/userguide/java_testing.html#sec :
java_test_fixtures

5.6で追加されました:https :
//docs.gradle.org/5.6/release-notes.html#test-fixtures-for-java-projects


Androidでのサポートに取り組んでいます。issuetracker.google.com / issues
Albert Vila Calvo

18

私は最近この問題に遭遇しましたが、これは答えを見つけるのが難しい問題です。

あなたがしている間違いは、プロジェクトがその主要な成果物と依存関係をエクスポートするのと同じ方法でそのテスト要素をエクスポートするべきだと考えています。

個人的にもっと成功したのは、Gradleで新しいプロジェクトを作ることでした。あなたの例では、私はそれに名前を付けます

プロジェクトA_Test-> src / main / java

プロジェクトA / src / test / javaに現在あるファイルをsrc / main / javaに入れます。プロジェクトAのtestCompile依存関係を作成します。プロジェクトA_Testの依存関係をコンパイルします。

次に、プロジェクトA_TestをプロジェクトBのtestCompile依存関係にします。

両方のプロジェクトの作成者の観点から見た場合、それは論理的ではありませんが、junitやscalatestなどのプロジェクトについて考えると、非常に理にかなっていると思います。これらのフレームワークはテスト関連ですが、独自のフレームワーク内の「テスト」ターゲットの一部とは見なされません-それらは、他のプロジェクトがたまたまテスト構成内で使用する主要な成果物を生成します。同じパターンに従ってください。

ここに記載されている他の回答を試してもうまくいかなかった(Gradle 1.9を使用)が、ここで説明するパターンは、とにかくクリーンなソリューションであることがわかりました。


はい、結局このアプローチを選択しました。
koma 2015年

これが最善の方法です。ただし、プロジェクトAにテストコードを保持し、A src / test / javaとB src / test / javaの両方の依存関係のみをA_Testに移動します。そして、プロジェクトA_TestにAとBの両方のtestImplementation依存します
エリックSillén

17

私はそれが古い質問であることを知っていますが、私は同じ問題を抱えていて、何が起こっているのかを理解するのにしばらく時間を費やしました。Gradle 1.9を使用しています。すべての変更はProjectBのbuild.gradle

ProjectBのテストでProjectAのテストクラスを使用するには:

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

sourceSetsプロパティがProjectAで利用可能であることを確認するには:

evaluationDependsOn(':ProjectA')

ProjectBをコンパイルするときに、ProjectAのテストクラスが実際に存在することを確認するには:

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

1
これも私にとってはうまくいきました.classesDir

11

Gradleプラグインとして利用可能な新しいtestJarベース(サポートされている依存関係)ソリューション:

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

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

ドキュメントから

マルチプロジェクトグラドルビルドがある場合、サブプロジェクト間にテストの依存関係がある可能性があります(これはおそらく、プロジェクトが適切に構造化されていないことのヒントです)。

たとえば、サブプロジェクトProject BがProject Aに依存し、BがAに対するコンパイル依存関係だけでなく、テスト依存関係も持っているプロジェクトを想定します。Bのテストをコンパイルして実行するには、Aのテストヘルパークラスが必要です。

デフォルトでは、gradleはプロジェクトのテストビルド出力からjarアーティファクトを作成しません。

このプラグインは、testArchives構成(testCompileに基づく)およびjarTestタスクを追加して、テストソースセットからjarを作成します(jarの名前に分類子テストが追加されています)。次に、BをAのtestArchives構成に依存させることができます(Aの推移的な依存関係も含まれます)。

Aでは、build.gradleにプラグインを追加します。

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

Bでは、次のようにtestArchives構成を参照します。

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

1
このリンクで質問に答えることができますが、回答の重要な部分をここに含め、参照用のリンクを提供することをお勧めします。リンクされたページが変更されると、リンクのみの回答が無効になる可能性があります。- 口コミより
イアン

数行のテキストが追加されました
demon101

とにかく、新しいgradleプラグインに関する情報が提供されています。
demon101

4
@ demon101がGradle 4.6で機能せず、エラーが発生するCould not get unknown property 'testClasses' for project ':core' of type org.gradle.api.Project.
Vignesh Sundar

11

以下のアップデートをお読みください。

JustACluelessNewbieで説明されている同様の問題がIntelliJ IDEAで発生します。問題は、依存関係がtestCompile project(':core').sourceSets.test.output実際に「gradleビルドタスクによって生成されたクラスに依存する」ことを意味することです。したがって、クラスがまだ生成されていないクリーンなプロジェクトを開いた場合、IDEAはそれらを認識せず、エラーを報告します。

この問題を修正するには、コンパイルされたクラスへの依存関係の横に、テストソースファイルへの依存関係を追加する必要があります。

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

モジュール設定->依存関係(テストスコープ)で IDEAが認識する依存関係を確認できます。

ところで これは良い解決策ではないので、リファクタリングを検討する価値があります。Gradle自体には、テストサポートクラスのみを含む特別なサブプロジェクトがあります。https://docs.gradle.org/current/userguide/test_kit.htmlを参照してください

更新2016-06-05 詳細提案された解決策について考えていますが、あまり気に入っていません。それにはいくつかの問題があります:

  1. IDEAに2つの依存関係を作成します。1つはソースをテストするためのポイントで、もう1つはコンパイルされたクラスに対するテストです。そして、これらの依存関係がIDEAによって認識される順序が重要です。モジュール設定->依存関係タブで依存関係の順序を変更することでそれを試すことができます。
  2. これらの依存関係を宣言すると、依存関係構造を不必要に汚染することになります。

それで、より良い解決策は何ですか?私の意見では、新しいカスタムソースセットを作成し、それに共有クラスを配置しています。実際、Gradleプロジェクトの作成者は、testFixturesソースセットを作成することでそれを行いました。

それを行うには、次のことを行う必要があります。

  1. ソースセットを作成し、必要な構成を追加します。Gradleプロジェクトで使用されているこのスクリプトプラグインを確認してください:https : //github.com/gradle/gradle/blob/v4.0.0/gradle/testFixtures.gradle
  2. 依存プロジェクトで適切な依存関係を宣言します。

    dependencies {
        testCompile project(path: ':module-with-shared-classes', configuration: 'testFixturesUsageCompile')
    }
    
  3. IDEAにGradleプロジェクトをインポートし、インポート中に「ソースセットごとに個別のモジュールを作成する」オプションを使用します。


1
@jannisが修正されました。ところで Gradleでは、そのグルービーベースのテストフィクスチャは、新しいKotlinするプラグイン移動ベース:github.com/gradle/gradle/blob/v5.0.0/buildSrc/subprojects/...
ヴァーツラフKužel

@VáclavKužel私はあなたのブログ投稿からあなたの興味深い解決策を見つけ、それは私の問題を非常にうまく解決しました。ありがとう;)
zaerymoghaddam

10

アンドロイドプロジェクト(gradle 2.2.0)をビルドしようとしたとき、Feslerのソリューションはうまくいきませんでした。だから私は必要なクラスを手動で参照する必要がありました:

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

1
わずかなタイプミス、プロジェクトの後の最後の引用符が欠落しています( ':A')。これは私にとってはうまくいきました、ありがとうm8
Ryan Newsom

1
Androidの場合、このアイデアはハック感じずに、私のために美しく働いstackoverflow.com/a/50869037/197141
アーベルク

@arbergはい、良いアプローチのようです。私が見る唯一の制限は、@VisibleForTestinglintルールに関するものです。not testフォルダーの下にある通常のモジュールからそのようなメソッドを呼び出すことはできません。
Beloo

5

私はパーティーに遅刻しました(現在はGradle v4.4です)が、これを見つけた人にとっては次のとおりです。

仮定:

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

プロジェクトB(Aからいくつかのテストクラスを必要とするプロジェクト)のbuild.gradleに移動し、以下を追加します。

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

または(プロジェクトの名前が「ProjectB」であると想定)

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

出来上がり!


3
質問はAndroidについては触れていません。開発者がAndroid用に開発しているかどうか、またはAndroid開発者専用かどうかにとらわれずに答えを出すことはできますか?
ロビングリーン

4

あなたがテストの間で共有する必要がモックの依存関係を持っている場合は、新しいプロジェクトを作成することができますprojectA-mockし、テストの依存関係としてにそれを追加ProjectAしてProjectB

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

これはモックの依存関係を共有するための明確なソリューションですがProjectAProjectB使用中の他のソリューションからテストを実行する必要がある場合。


共有モックケースの優れたソリューション!
ErikSillén19年

4

アーティファクトの依存関係を使用する場合:

  • ProjectBのソースクラスはProject Aのソースクラスに依存する
  • ProjectBのテストクラスはProject Aのテストクラスに依存する

次に、build.gradleの ProjectBの依存関係セクションは次のようになります。

dependencies {

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

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

}

これを機能させるには、ProjectAが-tests jar を作成し、生成するアーティファクトに含める必要があります。

ProjectAのbuild.gradleには、次のような構成が含まれている必要があります。

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

configurations {
    tests
}

artifacts {
    tests testsJar
    archives testsJar
}

jar.finalizedBy(testsJar)

ProjectAのアーティファクトがアーティファクトに公開されると、-tests jar が含まれます。

testCompile ProjectBの依存関係のセクションでは、内のクラスにもたらすでしょう-tests瓶。


開発目的でProjectB にフラット ProjectAのソースクラスとテストクラスを含める場合、ProjectBのbuild.gradleの依存関係セクションは次のようになります。

dependencies {

  compile project(':projecta')

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

}

1
残念ながら(Gradle 6では)フラットインクルードは、まさに私が望んでいたものでしたが、構成の「テスト」がなくなったため、機能しなくなりました。使い方println(configurations.joinToString("\n") { it.name + " - " + it.allDependencies.joinToString() })(kotlin buildscriptに)、私はまだ依存関係が存在していた構成を決定し、これらのGradleのすべてについて不平を言った: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

他の回答のいくつかは何らかの方法でエラーを引き起こしました-Gradleは他のプロジェクトからのテストクラスを検出しなかったか、Eclipseプロジェクトがインポート時に無効な依存関係を持っていました。誰かが同じ問題を抱えているなら、私は一緒に行くことを勧めます:

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

最初の行は、Eclipseに他のプロジェクトを依存関係としてリンクさせるため、すべてのソースが含まれており、最新の状態です。もう1つは、Gradleが実際にソースを確認できるようにする一方で、そうしたような無効な依存関係エラーを引き起こさないことtestCompile project(':core').sourceSets.test.outputです。


2

ここでKotlin DSLを使用している場合は、Gradleのドキュメントに従ってそのようなタスクを作成する必要があります。

以前の回答と同様に、テストクラスとメインクラスを混在させないように、テストクラスを共有する特別な構成をプロジェクト内に作成する必要があります。

簡単な手順

  1. では、プロジェクトA、あなたの中に追加する必要があります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. 次に、プロジェクトBの依存関係で、次のものを追加する必要がありますbuild.gradle.kts
dependencies {
    implementation(project(":ProjectA"))
    testImplementation(project(":ProjectA", "test"))
}

-1

プロジェクトB:

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

1.7-rc-2で動作するようです


2
また、Eclipseによるプロジェクトの処理に不要な複雑化を引き起こします。@NikitaSkvortsovによって提案されたソリューションが推奨されます。
フィッティング
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.