使用Gradle的多项目测试依赖关系

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

我的项目是这样的:

  • 项目A

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

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

我的项目Bbuild.gradle文件是这样的:

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

任务compileJava工作得很好,但是compileTestJava不编译来自项目A的测试文件。

113510 次浏览

简单的方法是在ProjectB中添加明确的任务依赖关系:

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

困难(但更明确)的方法是为ProjectA创建额外的工件配置:

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


configurations {
testArtifacts
}


artifacts {
testArtifacts myTestsJar
}

并为ProjectB添加testCompile依赖

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

不建议使用-对于Gradle 5.6及更高版本,使用这个答案

项目B中,您只需添加testCompile依赖关系:

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

使用Gradle 1.7进行测试。

在项目B中:

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

似乎在1.7-RC-2中工作

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

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

我个人更成功的是在Gradle做了一个新项目。在你的例子中,我会给它命名

项目A_测试 ->SRC/main/java

我会将您当前在项目a/SRC/test/Java中的文件放入SRC/main/Java中。将项目的任何TestCompile依赖项作为项目的Compile依赖项,并将其作为_Test.

然后使项目A_项目B的Test A TestCompile依赖项。

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

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

我知道这是一个老问题,但我只是有同样的问题,并花了一些时间弄清楚是怎么回事。我用的是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')

新的基于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的测试,我们需要一些 中的测试帮助器类。

默认情况

下,Gradle不会从测试版本创建JAR工件。 项目的输出。

这个插件添加了一个TestArchives配置(基于TestCompile) 和一个用于从测试源集创建jar的jartest任务(使用 向JAR的名称添加分类器测试)。然后我们可以依赖于B 的TestArchives配置(它还将包括 A的传递依赖)。

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

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

B中,我们引用 TestArchives配置如下:

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

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

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

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

请阅读下面的更新。

Justacluelessnewbie描述的类似问题也出现在IntelliJ IDEA中。问题是,依赖testCompile project(':core').sourceSets.test.output实际上表示:“依赖于Gradle构建任务生成的类”。因此,如果您打开尚未生成类的Clean Project,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中创建了两个依赖项。一个指向测试源,另一个指向已编译的类。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. Import Gradle project to IDEA and use the "create separate module per source set" option while importing.
当我尝试构建一个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")
}
}
}

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

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

这是一个共享mock依赖关系的清晰解决方案,但如果您需要从ProjectAProjectB中运行测试,请使用其他解决方案。

我来的太晚了(现在是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
}
}

瞧!

如果要使用人造物依赖关系,则具有:

  • 项目B的源类依赖于项目A的源类
  • ProjectB的测试类依赖于项目A的测试类

构建.gradle中的ProjectB的依赖关系部分应如下所示:

dependencies {


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


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


}

为此,项目需要构建一个ABC_JAR的_,并将其包含在它生成的工件中。

项目A的构建.gradle应包含如下配置:

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


configurations {
tests
}


artifacts {
tests testsJar
archives testsJar
}


jar.finalizedBy(testsJar)

当ProjectA的工件发布到您的Artifactory时,它们将包含一个_ABC,_0 jar.

ProjectB的Dependencies部分中的测试编译将引入-测试 jar中的类。


如果要在ProjectB中IncludeFlat ProjectA的源和测试类以进行开发,则ProjectB的构建.gradle中的依赖关系部分将如下所示:

dependencies {


compile project(':projecta')


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


}

具有javajava-library插件的在Gradle中,这现在作为第一类功能受到支持。模块还可以包括java-test-fixtures插件,该插件公开要与testFixtures帮助程序一起使用的帮助程序类和资源。这种方法相对于工件和分类器好处是:

  • 适当的依赖关系管理(实现/API)
  • 与测试代码很好的分离(单独的源代码集)
  • 不需要筛选出测试类来只公开实用程序
  • 由Gradle维护

例子

:modul:one

模块/one/build.gradle

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

模块/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")))
}

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

在这里,如果您使用的是科特林DSL,则应根据格拉德尔文档创建类似的任务。

与前面的一些回答一样,您需要在项目中创建一个特殊的配置,该配置将共享其测试类,这样您就不会将测试类和主类混合在一起。

简单步骤

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

尼基塔提到的安卓+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')

为Gradle 6.6.X创建test-jar

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

  • https://github.com/gradle/gradle/issues/11280.
  • https://gradle.org/whats-new/gradle-6/#better-builds.

但这太他妈的简单了,我只是不喜欢在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')

而且它很有效!

如果您正在努力使解决方案适应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)