对于具有compileOnly依赖项的单元测试,如何避免在运行时重新声明可用性的依赖项?

Chr*_*ord 5 testing dependencies gradle

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

  compileOnly group: 'org.apache.spark', name: 'spark-sql_2.11', version: '2.4.0.cloudera1'
Run Code Online (Sandbox Code Playgroud)

我依赖上面的火花工件这一事实与这个问题并没有真正的密切关系(我提供此信息是为了使示例更加具体。)

现在,假设我想为我的应用程序(或库,视情况而定)编写一些单元测试。使用 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'
Run Code Online (Sandbox Code Playgroud)

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

结论

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

subprojects {

  sourceSets {
    test.compileClasspath += configurations.compileOnly
    test.runtimeClasspath += configurations.compileOnly
  }
}
Run Code Online (Sandbox Code Playgroud)

Mik*_*ill 6

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

Gradle 最初关于仅编译依赖项的公告对此进行了进一步详细说明(https://blog.gradle.org/introducing-compile-only-dependency):

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

  • 编译时需要但运行时不需要的依赖项,例如纯源注释或注释处理器;
  • 编译时需要的依赖项,但仅在使用某些功能时才需要运行时依赖项,也称为可选依赖项
  • API在编译时需要但其实现由使用库、应用程序或运行时环境提供的依赖项。

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

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

// give test dependencies access to compileOnly dependencies to emulate providedCompile
configurations {
    testImplementation.extendsFrom compileOnly
}
Run Code Online (Sandbox Code Playgroud)

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