182

我有一个多项目配置,我想使用 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')
}

该任务compileJava工作得很好,但compileTestJava没有从Project A编译测试文件。

4

17 回答 17

141

已弃用 - 对于 Gradle 5.6 及更高版本,请使用此答案

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

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

使用 Gradle 1.7 测试。

于 2011-11-01T16:07:13.587 回答
68

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

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

例子

: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

模块/其他/build.gradle

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

模块/其他/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

于 2020-02-09T15:27:09.313 回答
67

简单的方法是在 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')
}
于 2011-04-13T11:40:49.103 回答
22

我最近自己也遇到了这个问题,伙计,这是一个很难找到答案的问题。

您所犯的错误是认为项目应该以与导出其主要工件和依赖项相同的方式导出其测试元素。

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

项目 A_Test -> src/main/java

我会将您当前在项目 A/src/test/java 中的文件放入 src/main/java。使您的项目 A 的任何 testCompile 依赖项编译项目 A_Test 的依赖项。

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

从两个项目的作者的角度来看,这是不合逻辑的,但我认为当你考虑像 junit 和 scalatest(以及其他)这样的项目时,这很有意义。即使这些框架与测试相关,它们在他们自己的框架中不被视为“测试”目标的一部分 - 它们产生其他项目恰好在其测试配置中使用的主要工件。您只想遵循相同的模式。

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

于 2014-01-31T16:13:00.727 回答
22

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

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

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

要确保该sourceSets属性可用于 ProjectA:

evaluationDependsOn(':ProjectA')

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

compileTestJava.dependsOn tasks.getByPath(':ProjectA:testClasses')
于 2014-02-05T14:47:32.603 回答
14

请阅读下面的更新。

JustACluelessNewbie 描述的类似问题发生在 IntelliJ IDEA 中。问题是依赖testCompile project(':core').sourceSets.test.output实际上意味着:“依赖于 gradle build task 生成的类”。因此,如果您打开尚未生成类的干净项目,IDEA 将无法识别它们并报告错误。

要解决此问题,您必须在对已编译类的依赖项旁边添加对测试源文件的依赖项。

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

您可以在Module Settings -> Dependencies (test scope)中观察 IDEA 识别的依赖关系。

顺便提一句。这不是很好的解决方案,因此值得考虑重构。Gradle 本身确实有仅包含测试支持类的特殊子项目。见https://docs.gradle.org/current/userguide/test_kit.html

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

  1. 它在 IDEA 中创建了两个依赖项。一个指向测试源另一个指向已编译的类。IDEA 以何种顺序识别这些依赖关系至关重要。您可以通过在 Module settings -> Dependencies 选项卡中更改依赖顺序来使用它。
  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. 将 Gradle 项目导入 IDEA 并在导入时使用“为每个源集创建单独的模块”选项。
于 2016-05-24T20:50:29.893 回答
11

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

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

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

从文档

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

例如假设一个项目,其中子项目 B 依赖于项目 A,而 B 不仅对 A 有编译依赖,而且还有测试依赖。为了编译和运行 B 的测试,我们需要 A 的一些测试助手类。

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

这个插件添加了一个 testArchives 配置(基于 testCompile)和一个 jarTest 任务来从测试源集创建一个 jar(将分类器 test 添加到 jar 的名称)。然后我们可以在 B 中依赖 A 的 testArchives 配置(这也将包括 A 的传递依赖)。

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

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

在 B 中,我们像这样引用 testArchives 配置:

dependencies {
    ...
    testCompile project (path: ':ProjectA', configuration: 'testArchives') 
}
于 2015-12-30T11:58:08.577 回答
11

当我尝试构建一个 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")
        }
    }
}
于 2016-10-05T08:13:08.440 回答
9

我参加聚会太晚了(现在是 Gradle v4.4),但对于其他任何发现这个的人来说:

假设:

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

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

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
    }
}

瞧!

于 2018-06-22T12:11:24.690 回答
6

在这里,如果您使用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"))
}
于 2020-05-08T15:16:08.900 回答
6

为 Gradle 6.6.x 创建 test-jar

我知道有很多消息来源告诉你,这是不行的,fe:

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

所以在模块A中:

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

在模块 B 中:

testImplementation project(':moduleA')
testImplementation project(path: ':moduleA', configuration: 'tests')

它只是工作!

于 2020-09-09T16:27:19.550 回答
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")

}

为此,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。

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


如果您想在ProjectB中包含 Flat ProjectA 的源代码和测试类以用于开发目的,那么 ProjectB 的build.gradle中的依赖项部分将如下所示:

dependencies {

  compile project(':projecta')

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

}
于 2019-02-11T23:54:59.260 回答
4

如果您有需要在测试之间共享的模拟依赖项,您可以创建新项目projectA-mock,然后将其作为测试依赖项添加到ProjectAand ProjectB

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

这是共享模拟依赖项的明确解决方案,但如果您需要从ProjectA正在ProjectB使用的其他解决方案运行测试。

于 2018-05-14T10:46:34.277 回答
4

Nikita提到的针对Android + Kotlin的解决方案如下所示:

task jarTests(type: Jar, dependsOn: "assembleDebugUnitTest") {
    getArchiveClassifier().set('tests')
    from "$buildDir/tmp/kotlin-classes/debugUnitTest"
}

configurations {
    unitTestArtifact
}

artifacts {
    unitTestArtifact jarTests
}

将使用依赖项的项目的 Gradle:

testImplementation project(path: ':shared', configuration: 'unitTestArtifact')
于 2020-08-07T08:45:58.113 回答
2

其他一些答案以某种方式导致错误 - Gradle 未检测到来自其他项目的测试类或 Eclipse 项目在导入时具有无效的依赖项。如果有人有同样的问题,我建议使用:

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

第一行强制 Eclipse 将其他项目链接为依赖项,因此所有源都包含在内并且是最新的。第二个允许 Gradle 实际查看源,而不会像这样testCompile project(':core').sourceSets.test.output做那样导致任何无效的依赖错误。

于 2016-05-24T20:14:36.257 回答
0

如果您正在努力使解决方案适应 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) 
于 2022-02-09T08:57:06.370 回答
-1

在项目 B 中:

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

似乎在 1.7-rc-2 中工作

于 2013-08-06T21:43:35.927 回答