首页 > 解决方案 > 对于具有 compileOnly 依赖项的单元测试,我如何避免在运行时重新声明可用性的依赖项?

问题描述

我目前正在使用 Gradle 构建一个项目,它依赖于我在编译时需要的第三方组件,但它将在运行时提供。在 maven 中,我将这个依赖声明为provided,在 Gradle 中,我将其声明如下:

  compileOnly group: 'org.apache.spark', name: 'spark-sql_2.11', version: '2.4.0.cloudera1'

我依赖于上述火花工件这一事实与问题并不密切相关(我提供此信息是为了使示例更加具体。)

现在,假设我想为我的应用程序(或库,视情况而定)编写一些单元测试。使用 Gradle 时,我想出如何做到这一点的唯一方法是笨拙的:我将依赖项重新声明为 testCompile 依赖项,并且我的测试能够运行:

  compileOnly group: 'org.apache.spark', name: 'spark-sql_2.11', version: '2.4.0.cloudera1'
  testCompile group: 'org.apache.spark', name: 'spark-sql_2.11', version: '2.4.0.cloudera1'

我真的不喜欢两次声明我的依赖关系的重复和混乱,我想知道在 Gradle 中是否有更好的方法来做到这一点?

结论

Mike 的回答让我选择了我选择的解决方案,即把它放在我的多项目构建的顶级 gradle 文件中。

subprojects {

  sourceSets {
    test.compileClasspath += configurations.compileOnly
    test.runtimeClasspath += configurations.compileOnly
  }
}

标签: testinggradledependencies

解决方案


这实际上是一种非常标准的方式来声明 Gradle 依赖项。有很多情况下compileOnly可以使用依赖项,但并非所有这些都需要在运行时提供依赖项(与 Maven 的provided范围所暗示的不同)。

这在 Gradle 的仅编译依赖项的初始公告中进一步详细说明(https://blog.gradle.org/introducing-compile-only-dependencies):

仅编译依赖项解决了许多用例,包括:

  • 编译时需要但运行时从不需要的依赖项,例如仅源注解或注解处理器;
  • 编译时需要的依赖项,但只有在使用某些功能时才需要在运行时,即可选依赖项
  • 在编译时需要其API但其实现将由消费库、应用程序或运行时环境提供的依赖项。

您所拥有的是为主要源声明仅编译依赖项的惯用方式,这也是您的测试源的运行时依赖项(尽管从技术上讲,最近的 Gradle 版本建议您用testCompile配置替换不推荐使用的testImplementation配置)。

然而,Gradle 的一大优点是它是高度可定制的。内置配置,如compileOnlytestImplementation可以修改。如果您希望更改内置行为,您可以修改testImplementation配置以扩展compileOnly配置,这将导致解析compileOnly时包含所有依赖项:testImplementation

// give test dependencies access to compileOnly dependencies to emulate providedCompile
configurations {
    testImplementation.extendsFrom compileOnly
}

来源:https ://discuss.gradle.org/t/compileonly-dependencies-are-not-available-in-tests/15366/8


推荐阅读