强制 Gradle 使用较早的依赖版本进行测试

Forcing Gradle to use an earlier dependency version for testing

有没有一种方法可以构建一个 Gradle 构建文件来强制测试阶段使用比用于编译和打包的依赖项更早的版本?

我正在尝试 set up an HBase mini-cluster via HBaseTestingUtility to test my project; unfortunately, HBaseTestingUtility relies on an old version of Guava (14.0.1 seems to work), while the rest of my project uses 18.0. Here are excerpts of my build script, as-is (I'm also using the Gradle test-sets plugin by unbroken-dome 创建两组独立的测试):

plugins {
    id 'org.unbroken-dome.test-sets' version '1.2.0'
}

apply plugin: 'java'

ext.verGuava = '18.0'
ext.verGuavaTEST = '14.0.1'

testSets {
    testUnit { dirName = 'test/unit' }
    testIntegration { dirName = 'test/integration' }
}

configurations {
    provided
    provided {
        extendsFrom(compile)
    }
    testIntConf
    testIntConf {
        extendsFrom(provided)
        resolutionStrategy {
            force "com.google.guava:guava:${verGuavaTEST}"
            forcedModules = ["com.google.guava:guava:${verGuavaTEST}"]
        }
    }
}

sourceSets {
    main.compileClasspath += configurations.provided
    testUnit.compileClasspath += configurations.provided
    testUnit.runtimeClasspath += configurations.provided
    testIntegration.compileClasspath += configurations.testIntConf
    testIntegration.runtimeClasspath += configurations.testIntConf
}

dependencies {
    provided "org.apache.hbase:hbase-client:${verHBase}"
    provided "org.apache.hbase:hbase-common:${verHBase}"
    compile "org.testng:testng:${verTestNG}"
    testIntegrationCompile group:'org.apache.hadoop', name:'hadoop-common', version:"${verHadoop}", classifier: 'tests'
    testIntegrationCompile group:'org.apache.hbase', name:'hbase-server', version:"${verHBase}"
    testIntegrationCompile group:'org.apache.hbase', name:'hbase-server', version:"${verHBase}", classifier: 'tests'
    testIntegrationCompile group:'org.apache.hbase', name:'hbase-hadoop-compat', version:"${verHBase}"
    testIntegrationCompile group:'org.apache.hbase', name:'hbase-hadoop-compat', version:"${verHBase}", classifier: 'tests'
    testIntegrationCompile group:'org.apache.hbase', name:'hbase-hadoop2-compat', version:"${verHBase}"
    testIntegrationCompile group:'org.apache.hbase', name:'hbase-hadoop2-compat', version:"${verHBase}", classifier: 'tests'
    testIntegrationCompile group:'org.apache.hadoop', name:'hadoop-hdfs', version:"${verHadoop}"
    testIntegrationCompile group:'org.apache.hadoop', name:'hadoop-hdfs', version:"${verHadoop}", classifier: 'tests'
}

testUnit {
    useTestNG()
    logger.info "@@@ Classpath (UNIT testing): ${classpath.getFiles().collect({it.toString()}).inject('\n') {acc, next -> acc + next + '\n'}}"
    logger.info "@@@ SystemProps (UNIT testing): ${System.getProperties().collect({it.toString()}).inject('\n') {acc, next -> acc + next + '\n'}}"
}

testIntegration {
    useTestNG()
    systemProperty "java.net.preferIPv4Stack", "true"
    logger.info "@@@ Classpath (INTEGRATION testing): ${classpath.getFiles().collect({it.toString()}).inject('\n') {acc, next -> acc + next + '\n'}}"
    logger.info "@@@ SysProps (INTEGRATION testing): ${System.getProperties().collect({it.toString()}).inject('\n') {acc, next -> acc + next + '\n'}}"
}

当我 运行 通过此脚本构建时,我得到以下输出,这似乎表明 Guava 14.0.1 已 添加 到 testIntegration 的类路径目标,而不是 replacing Guava 18.0:

@@@ Classpath (UNIT testing):
/home/user/.gradle/caches/modules-2/files-2.1/com.google.guava/guava/18.0/cce0823396aa693798f8882e64213b1772032b09/guava-18.0.jar
@@@ Classpath (INTEGRATION testing):
/home/user/.gradle/caches/modules-2/files-2.1/com.google.guava/guava/18.0/cce0823396aa693798f8882e64213b1772032b09/guava-18.0.jar
/home/user/.gradle/caches/modules-2/files-2.1/com.google.guava/guava/14.0.1/69e12f4c6aeac392555f1ea86fab82b5e5e31ad4/guava-14.0.1.jar

这种行为可能是意料之中的; API 表示 ResolutionStrategy.force(...) 将工件附加到要考虑的列表中。

如何指示 Gradle 从 testIntegration 目标的类路径中完全删除 Guava 18.0?

我尝试更改 sourceSets 部分以使用 = 而不是 +=:[=23 分配类路径=]

sourceSets {
    ...
    testIntegration.compileClasspath = configurations.testIntConf
    testIntegration.runtimeClasspath = configurations.testIntConf
}

就消除 Guava 18.0(并保留 14.0.1)而言,这具有预期的效果,但它似乎阻止了 Gradle 检测 testIntegration 源文件的位置,对于某些原因,所以 testIntegration 测试永远不会编译或执行。

我还尝试了一些从继承配置中清除 Guava 的变体,例如:

configurations {
    provided
    provided {
        extendsFrom(compile)
    }
    testIntConf
    testIntConf {
        extendsFrom(provided.copy {
            exclude group:"com.google.guava", module:"guava"
        })
        resolutionStrategy {
            force "com.google.guava:guava:${verGuavaTEST}"
            forcedModules = ["com.google.guava:guava:${verGuavaTEST}"]
        }
    }
}

以上(以及我尝试过的所有其他变体)确实成功地消除了类路径中 Guava 工件的重复,但它们似乎使 resolutionStrategy 无效,因为已解析的工件总是较新的版本 (18.0) 即使在 testIntegration.

虽然这可能不是最优雅的解决方案(而且我仍然对更简洁的解决方案感兴趣,如果它存在的话),一种似乎有效的方法是创建一个完全独立的配置,其中包含较新的 Guava 依赖项 ,然后使用FileCollection#minus从testIntegration目标本身的类路径中减去该配置。

首先,创建配置;我在这里称它为 guava,因为它的唯一目的是包含我想从 testIntegration 类路径中排除的 Guava 18.0 工件:

configurations {
    guava
    ...
}

(配置应该单独包含 Guava 工件,因此它应该 extendsFrom 任何其他配置。)

其次,将要从类路径中排除的工件添加到新创建配置的依赖项列表中。在这种情况下,我知道主要配置将 com.google.guava:guava 解析为版本 18.0,因此我将对该版本的 Guava 的依赖添加到 guava 配置:

dependencies {
    guava group:'com.google.guava', name:'guava', version:"${verGuava}"
    ...
}

第三,在 Gradle 目标中的 classpath 上调用 FileCollection#minus,其中您想要强制依赖项的早期版本,以排除较新的依赖项。我上面的 testIntegration 块是这样转换的:

testIntegration {
    classpath = classpath.minus(configurations.guava);
    ...
}

因此,Gradle 构建中它的工作原理的快速总结是:

  1. 创建一个配置,其中extendsFrom主要配置(例如compile),然后使用ResolutionStrategy#force and ResolutionStrategy#forcedModules添加早期版本的依赖于该配置的依赖列表。
  2. 创建一个 second 配置,它不从任何东西扩展,旨在容纳 较新的 版本的依赖项。
  3. sourceSets 中,将第 1 步中创建的配置附加到 compileClasspathruntimeClasspath 中,用于您希望强制使用较早依赖项版本的目标。
  4. dependencies 中,将工件的较新版本添加为步骤 2 中创建的配置的依赖项。
  5. 目标块中的 classpath 现在包含默认依赖项的联合 加上 早期版本,作为步骤 1 和 3 中采取的操作的结果. 要删除 较新的 版本,请将 classpath 设置为 classpath.minus(newerDependencyConfiguration),其中 newerDependencyConfiguration 是在步骤 2 中创建的

我遇到了同样的问题,但版本更简单。因为我没有区分集成测试和单元测试。使用它似乎为 test

提供了正确的番石榴依赖性
   configurations {
        all{
            resolutionStrategy {
                force 'com.fasterxml.jackson.core:jackson-databind:2.4.4'
            }
        }
        testCompile{
            resolutionStrategy {
                force 'com.google.guava:guava:14.0.1'
            }
        }
    }
dependencies {
 testCompile group: 'org.apache.hbase', name: 'hbase-testing-util', version: '1.2.4'
}