使用gradle构建多项目测试依赖关系

1u4esq0p  于 2021-07-16  发布在  Java
关注(0)|答案(16)|浏览(488)

我有一个多项目配置,我想使用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 不从项目a编译测试文件。

mctunoxg

mctunoxg1#

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

在项目b中,您只需要添加 testCompile 附属国:

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

用gradle 1.7测试。

tgabmvqs

tgabmvqs2#

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

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

困难的(但更清楚的)方法是为projecta创建额外的工件配置:

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

configurations {
  testArtifacts
}

artifacts {
   testArtifacts myTestsJar
}

并添加 testCompile 项目B的依赖关系

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

mgdq6dx13#

这是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\测试\夹具
在5.6中增加了:
https://docs.gradle.org/5.6/release-notes.html#test-java项目的fixture

hiz5n14c

hiz5n14c4#

我最近也遇到过这个问题,这是一个很难找到答案的问题。
您所犯的错误是认为项目应该以导出其主要工件和依赖项的相同方式导出其测试元素。
我个人更成功的是在grad尔做了一个新项目。在你的例子中,我会命名它
项目测试->src/main/java
我将把您当前在项目a/src/test/java中的文件放入src/main/java中。使项目的任何testcompile依赖项成为项目的compile依赖项。
然后使项目a\u test成为项目b的testcompile依赖项。
从这两个项目的作者的Angular 来看,这是不符合逻辑的,但我认为当您考虑像junit和scalatest(以及其他)这样的项目时,这是很有意义的。即使这些框架是与测试相关的,它们也不被认为是它们自己框架中“测试”目标的一部分——它们产生了其他项目恰好在它们的测试配置中使用的主要构件。你只想遵循同样的模式。
尝试做这里列出的其他答案对我个人来说不起作用(使用gradle1.9),但我发现我在这里描述的模式无论如何都是一个更干净的解决方案。

hpcdzsge

hpcdzsge5#

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

5gfr0r5j6#

请阅读下面的更新。
justacluelessnewbie描述的类似问题也出现在intellij idea中。问题是这种依赖性 testCompile project(':core').sourceSets.test.output 实际上意思是:“依赖于gradle build任务生成的类”。所以,如果你打开一个干净的项目,其中类还没有生成,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更多我正在考虑建议的解决方案我不太喜欢它。它几乎没有什么问题:
它在idea中创建了两个依赖关系。一个指向测试源,另一个指向编译类。这些依赖性被idea识别的顺序是至关重要的。您可以通过在“模块设置”->“依赖项”选项卡中更改依赖项顺序来使用它。
通过声明这些依赖关系,您将不必要地污染依赖关系结构。
那么更好的解决方案是什么呢?在我看来,这是在创建新的自定义源代码集,并将共享类放入其中。实际上gradle项目的作者是通过创建testfixtures源集来实现的。
要做到这一点,你只需:
创建源集并添加必要的配置。检查gradle项目中使用的脚本插件:https://github.com/gradle/gradle/blob/v4.0.0/gradle/testfixtures.gradle
在依赖项目中声明正确的依赖关系:

dependencies {
    testCompile project(path: ':module-with-shared-classes', configuration: 'testFixturesUsageCompile')
}

将gradle项目导入idea,并在导入时使用“为每个源集创建单独的模块”选项。

vqlkdk9b

vqlkdk9b7#

新的基于testjar(支持trnsitive dependencies)的解决方案作为gradle插件提供:
https://github.com/hauner/gradle-plugins/tree/master/jartest
https://plugins.gradle.org/plugin/com.github.hauner.jartest/1.0
来自文档
如果您有一个多项目渐变构建,那么子项目之间可能有测试依赖关系(这可能暗示您的项目没有良好的结构)。
例如,假设一个项目,其中子项目b依赖于项目a,而b不仅对a有编译依赖,而且还有测试依赖。为了编译和运行b的测试,我们需要一些来自a的测试助手类。
默认情况下,gradle不会从项目的测试构建输出创建jar工件。
这个插件添加了一个testarchives配置(基于testcompile)和一个jartest任务,以从测试源集创建一个jar(将分类器测试添加到jar的名称中)。然后我们可以在b中依赖于a的testarchives配置(其中还包括a的可传递依赖项)。
在一个示例中,我们会将插件添加到build.gradle: apply plugin: 'com.github.hauner.jarTest' 在b中,我们引用testarchives配置如下:

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

u0sqgete8#

当我尝试构建一个android项目(gradle2.2.0)时,fesler的解决方案对我来说并不奏效。所以我不得不手动引用必需的类:

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

wwodge7n9#

我来晚了(现在是gradle v4.4),但是对于其他发现这个的人:
假设:

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

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

瞧!

o0lyfsai

o0lyfsai10#

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

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

这是共享模拟依赖项的明确解决方案,但是如果您需要从 ProjectAProjectB 使用其他解决方案。

jvidinwx

jvidinwx11#

如果要使用工件依赖项来具有:
projectb的源类依赖于projecta的源类
projectb的测试类依赖于projecta的测试类
那么build.gradle中projectb的dependencies部分应该如下所示:

dependencies {

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

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

}

为了让它工作,projecta需要构建一个测试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的dependencies部分中的testcompile将引入-tests jar中的类。
如果您想在projectb中包含deflat projecta的源代码和测试类以用于开发,那么projectb的build.gradle中的dependencies部分将如下所示:

dependencies {

  compile project(':projecta')

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

}
ymdaylpp

ymdaylpp12#

如果您使用的是kotlindsl,那么应该根据gradle文档创建这样的任务。
与前面的一些答案一样,您需要在项目中创建一个特殊的配置来共享它的tests类,这样您就不会混合test和main类。

简单的步骤

在项目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"])
}

然后在项目b中的依赖项中,需要添加 build.gradle.kts :

dependencies {
    implementation(project(":ProjectA"))
    testImplementation(project(":ProjectA", "test"))
}
xqnpmsa8

xqnpmsa813#

为gradle6.6.x创建测试jar

我知道有很多消息来源告诉你,这不好,菲:
https://github.com/gradle/gradle/issues/11280
https://gradle.org/whats-new/gradle-6/#better-构建
但这太简单了,我只是不喜欢把公共测试类单独放在 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: ':modukeA', configuration: 'tests')

而且还真管用!

pzfprimi

pzfprimi14#

nikita提到的android+kotlin解决方案如下:

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

configurations {
    unitTestArtifact
}

artifacts {
    unitTestArtifact jarTests
}

将使用依赖项的项目的渐变:

testImplementation project(path: ':shared', configuration: 'unitTestArtifact')
y4ekin9u

y4ekin9u15#

其他一些答案以某种方式导致了错误——gradle没有从其他项目检测到测试类,或者eclipse项目在导入时具有无效的依赖关系。如果有人有同样的问题,我建议你:

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

第一行强制eclipse将另一个项目作为依赖项进行链接,因此所有源代码都包含在内并且是最新的。第二种方法允许gradle实际查看源代码,同时不会导致任何无效的依赖性错误,如 testCompile project(':core').sourceSets.test.output 做。

相关问题