使用gradle的多项目测试依赖项

mat*_*thd 133 dependencies build multi-project gradle

我有一个多项目配置,我想使用gradle.

我的项目是这样的:

  • 项目A.

    • - > src/main/java
    • - > src/test/java
  • 项目B.

    • - > src/main/java(取决于src/main/java项目A)
    • - > src/test/java(取决于src/test/java项目A)

我的Project B build.gradle文件是这样的:

apply plugin: 'java'
dependencies {
  compile project(':ProjectA')
}
Run Code Online (Sandbox Code Playgroud)

该任务compileJava工作得很好,但compileTestJava不会从项目A编译测试文件.

Fes*_*ler 114

弃用

Project B中,您只需添加一个testCompile依赖项:

dependencies {
  ...
  testCompile project(':A').sourceSets.test.output
}
Run Code Online (Sandbox Code Playgroud)

用Gradle 1.7测试.

  • 这在Gradle 1.3中不起作用,因为sourceSets不再是项目的公共属性. (12认同)
  • 不要这样做,项目不应该进入其他项目.而是使用Nikita的答案,正确地将其建模为项目依赖. (8认同)
  • 结果是不推荐使用classes属性 - 而是使用输出. (7认同)
  • 请记住,在构建结构实际有效之前,上述解决方案至少需要一个`gradle testClasses`.例如,Eclipse插件不允许您在此之前导入项目.真的很遗憾`testCompile项目(':'')`不起作用.@DavidPärsson:自从Fesler用Gradle 1.7测试以来,"Gradle 1.3"与"不再"相矛盾. (3认同)
  • 不适合我.循环依赖失败:compileTestJava\---:testClasses\---:compileTestJava(*) (2认同)

Nik*_*sov 60

简单的方法是在ProjectB中添加显式任务依赖:

compileTestJava.dependsOn tasks.getByPath(':ProjectA:testClasses')
Run Code Online (Sandbox Code Playgroud)

困难(但更清晰)的方法是为ProjectA创建其他工件配置:

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

configurations {
  testArtifacts
}

artifacts {
   testArtifacts myTestsJar
}
Run Code Online (Sandbox Code Playgroud)

testCompile为ProjectB 添加依赖项

apply plugin: 'java'
dependencies {
  compile project(':ProjectA')
  testCompile project(path: ':ProjectA', configuration: 'testArtifacts')
}
Run Code Online (Sandbox Code Playgroud)

  • 在Gradle 1.8中,您可能需要`来自sourceSets.test.output`并且可能需要`classifier ='tests'来代替`// pack your you need ... (7认同)
  • 这在 Gradle 4.7 中对我有用。他们现在在 https://docs.gradle.org/current/dsl/org.gradle.api.artifacts.dsl.ArtifactHandler.html 上有一些关于该方法的文档 (3认同)
  • 我尝试了这个(简单的方法),虽然这确保它构建了testClasses,但它没有将测试路径添加到CLASSPATH,因此依赖于ProjectA测试类的ProjectB测试仍然无法构建. (2认同)

TWi*_*Rob 57

现在,这在 Gradle 中作为一流功能得到支持。带有javajava-library插件的模块还可以包含一个java-test-fixtures插件,该插件公开助手类和要与testFixtures助手一起使用的资源。这种方法对工件和分类器的好处是:

  • 适当的依赖管理(实现/api)
  • 与测试代码很好的分离(单独的源集)
  • 无需过滤测试类以仅公开实用程序
  • 由 Gradle 维护

例子

:modul:one

模块/一个/build.gradle

plugins {
  id "java-library" // or "java"
  id "java-test-fixtures"
}
Run Code Online (Sandbox Code Playgroud)

模块/一个/src/testFixtures/java/com/example/Helper.java

package com.example;
public class Helper {}
Run Code Online (Sandbox Code Playgroud)

:modul:other

模块/其他/build.gradle

plugins {
  id "java" // or "java-library"
}
dependencies {
  testImplementation(testFixtures(project(":modul:one")))
}
Run Code Online (Sandbox Code Playgroud)

模块/其他/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
  }
}
Run Code Online (Sandbox Code Playgroud)

进一步阅读

有关更多信息,请参阅文档: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 上支持此功能,请参阅 https://issuetracker.google.com/issues/139762443 和 https://issuetracker.google.com/issues/139438142 (5认同)

小智 17

我知道这是一个老问题,但我遇到了同样的问题,花了一些时间弄清楚发生了什么.我正在使用Gradle 1.9.所有更改都应该在ProjectB中build.gradle

要在ProjectB的测试中使用ProjectA中的测试类:

testCompile files(project(':ProjectA').sourceSets.test.output.classesDir)
Run Code Online (Sandbox Code Playgroud)

要确保sourceSetsProjectA可以使用该属性:

evaluationDependsOn(':ProjectA')
Run Code Online (Sandbox Code Playgroud)

为了确保ProjectA中的测试类实际存在,在编译ProjectB时:

compileTestJava.dependsOn tasks.getByPath(':ProjectA:testClasses')
Run Code Online (Sandbox Code Playgroud)

  • 这也对我有用,只是我不得不省略`.classesDir`。 (2认同)

Mar*_*der 16

我最近自己也遇到过这个问题,而男人这是一个很难找到答案的问题.

你犯的错误是认为项目应该以导出它的主要工件和依赖项的方式导出它的测试元素.

我个人在Gradle上创造了一个新项目取得了更大的成功.在你的例子中,我会命名它

项目A_Test - > src/main/java

我会把你目前在Project A/src/test/java中的文件放到src/main/java中.使Project A_Test的任何testCompile依赖项成为Project A_Test的编译依赖项.

然后使Project A_Test成为Project B的testCompile依赖项.

这是不符合逻辑的,当你从两个项目的作者的角度来冲去,但我认为它使一个很大的意义,当你考虑一下像JUnit和scalatest项目(和其他人.即使这些框架正在测试相关的,他们不被视为自己框架中"测试"目标的一部分 - 它们产生其他项目恰好在其测试配置中使用的主要工件.您只想遵循相同的模式.

尝试做这里列出的其他答案对我个人不起作用(使用Gradle 1.9),但我发现我在这里描述的模式无论如何都是一个更清洁的解决方案.


dem*_*101 11

新的基于testJar(支持的trnsitive dependancies)解决方案可用作gradle插件:

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

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

从文档

如果您有一个多项目gradle构建,则可能在子项目之间存在测试依赖关系(这可能暗示您的项目结构不合理).

例如,假设子项目Project B依赖于项目A和B的项目不仅具有对A的编译依赖性,而且还具有测试依赖性.要编译和运行B的测试,我们需要一些来自A的测试助手类.

默认情况下,gradle不会从项目的测试构建输出中创建jar工件.

此插件添加了testArchives配置(基于testCompile)和jarTest任务,以从测试源集创建jar(将分类器测试添加到jar的名称).然后我们可以在B的testArchives配置中依赖于B(它还将包括A的传递依赖性).

在A中我们将插件添加到build.gradle:

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

在B中,我们引用testArchives配置,如下所示:

dependencies {
    ...
    testCompile project (path: ':ProjectA', configuration: 'testArchives') 
}
Run Code Online (Sandbox Code Playgroud)

  • @ demon101在Gradle 4.6中不起作用,出现错误“无法获取类型为org.gradle.api.Project的项目':core'的未知属性'testClasses'。” (4认同)

Vác*_*žel 9

请阅读下面的更新.

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
Run Code Online (Sandbox Code Playgroud)

您可以在模块设置 - >依赖关系(测试范围)中观察IDEA识别的依赖关系.

顺便说一句.这不是一个好的解决方案,所以重构值得考虑.Gradle本身只有包含测试支持类的特殊子项目.请参阅https://docs.gradle.org/current/userguide/test_kit.html

更新2016-06-05 更多我正在考虑提议的解决方案,而不是我喜欢它.它有几个问题:

  1. 它在IDEA中创建了两个依赖项.一个指向另一个测试来源编译类.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')
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 将Gradle项目导入到IDEA,并在导入时使用"为每个源集创建单独的模块"选项.


Bel*_*loo 8

当我尝试构建一个Android项目(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")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 在gradle 4.4上为我工作的最简单的解决方案:-) (2认同)

tri*_*ogy 8

我参加聚会太晚了(现在是 Gradle v4.4)但是对于其他发现此问题的人:

假设:

~/allProjects
|
|-/ProjectA/module-a/src/test/java
|
|-/ProjectB/module-b/src/test/java
Run Code Online (Sandbox Code Playgroud)

转到build.gradle项目 B(需要 A 中的一些测试类的项目)并添加以下内容:

~/allProjects
|
|-/ProjectA/module-a/src/test/java
|
|-/ProjectB/module-b/src/test/java
Run Code Online (Sandbox Code Playgroud)

或(假设您的项目名为ProjectB

sourceSets {
    String sharedTestDir = "${projectDir}"+'/module-b/src/test/java'
    test {
        java.srcDir sharedTestDir
    }
}
Run Code Online (Sandbox Code Playgroud)

瞧!

  • 这个问题没有提到Android。您能否让您的答案与开发人员是否为 Android 开发,还是仅适用于 Android 开发人员无关? (3认同)
  • 我从事一个有周期的项目,所以这个答案是唯一一个或多或少干净的答案。作为参考,我在需要从 `projectExusingTests` 进行测试的项目中放置了代码片段(kotlin 版本): `sourceSets { test { java.srcDir(project(":projectExformingTests").file("src/test/java")) } }` (2认同)

Ata*_*ais 7

为 Gradle 6.6.x 创建测试 jar

我知道有很多消息来源告诉你,这是不对的,例如:

但这太简单了,我只是不喜欢在testFixtures文件夹中单独放置通用测试类的想法。

所以在模块A中:

task jarTests(type: Jar, dependsOn: testClasses) {
    classifier = 'tests'
    from sourceSets.test.output
}
configurations {
    tests {
        extendsFrom testRuntime
    }
}
artifacts {
    tests jarTests
}
Run Code Online (Sandbox Code Playgroud)

在模块 B 中:

testImplementation project(':moduleA')
testImplementation project(path: ':moduleA', configuration: 'tests')
Run Code Online (Sandbox Code Playgroud)

而且它确实有效!


Jom*_*n68 5

如果您想使用工件依赖项来拥有:

  • 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")

}
Run Code Online (Sandbox Code Playgroud)

为此,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)
Run Code Online (Sandbox Code Playgroud)

当 ProjectA 的工件发布到您的工件时,它们将包含一个-tests jar。

ProjectB 的依赖项部分中的testCompile将引入-tests jar中的类。


如果你想includeFlat项目A的来源和测试类的项目B为发展目的则依赖于项目B的部分的build.gradle是这样的:

dependencies {

  compile project(':projecta')

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

}
Run Code Online (Sandbox Code Playgroud)

  • 不幸的是(在 Gradle 6 中)平面包含(这正是我想要的)不再工作,因为不再有配置“测试”。使用 `println(configurations.joinToString("\n") { it.name + " - " + it.allDependency.joinToString() })` (在 kotlin 构建脚本中),我确定了哪些配置仍然存在并且具有依赖关系,但是对于所有这些 Gradle 抱怨:“在‘project :sdk’上选择了配置‘testCompileClasspath’,但它不能用作项目依赖项,因为它不适合其他组件使用。” (2认同)

Syl*_*are 5

在这里,如果您使用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"])
}
Run Code Online (Sandbox Code Playgroud)
  1. 然后在依赖项中的项目 B中,您需要添加build.gradle.kts
dependencies {
    implementation(project(":ProjectA"))
    testImplementation(project(":ProjectA", "test"))
}
Run Code Online (Sandbox Code Playgroud)


小智 5

如果您正在努力使解决方案适应 Gradle Kotlin DSL,则这相当于:

configurations {
    register("testClasses") {
        extendsFrom(testImplementation.get())
    }
}
val testJar = tasks.register<Jar>("testJar") {
    archiveClassifier.set("test")
    from(sourceSets.test)
}
artifacts.add("testClasses", testJar) 
Run Code Online (Sandbox Code Playgroud)