简体   繁体   中英

Forcing Gradle to use an earlier dependency version for testing

Is there a way to construct a Gradle build file to force the test phase to use an earlier version of a dependency than the one used for compilation and and packaging?

I'm attempting to 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 to create two separate sets of tests):

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

When I run a build via this script, I get the following output which seems to show that Guava 14.0.1 was added to the classpath for the testIntegration target, rather than 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

This behavior is probably to be expected; the API indicates that ResolutionStrategy.force(...) appends artifacts to the list to be considered.

How can I direct Gradle to eliminate Guava 18.0 from the classpath for the testIntegration target entirely?

I have tried changing the sourceSets section to assign the classpaths using = rather than += :

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

This has the desired effect as far as eliminating Guava 18.0 (and retaining 14.0.1), but it seems to prevent Gradle from detecting the location of the testIntegration source files, for some reason, so the testIntegration tests are never compiled or executed.

I have also tried a few variations on purging Guava from the inherited configuration, such as the following:

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

The above (and all other variations I've tried) do successfully eliminate the duplication of the Guava artifact in the classpath, but they seem to nullify the resolutionStrategy , as the resolved artifact is always the newer version (18.0) even in testIntegration .

While perhaps not the most elegant solution (and I'd still be interested in a cleaner one, if it exists), an approach which seems to work is to create a completely separate configuration which contains the newer Guava dependency only , then use FileCollection#minus to subtract that configuration from the classpath within the testIntegration target itself.

Firstly, create the configuration; I call it guava here since its sole purpose is to contain the Guava 18.0 artifact that I want to exclude from the testIntegration classpath:

configurations {
    guava
    ...
}

(The configuration should contain the Guava artifacts in isolation, so it should not extendsFrom any other config.)

Secondly, add the artifact to be excluded from the classpath to the dependency list for the newly-created configuration. In this case, I know that the main configurations resolve com.google.guava:guava to version 18.0, so I add a dependency on that version of Guava to the guava configuration:

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

Thirdly, invoke FileCollection#minus on classpath in the Gradle target wherein you want to force the earlier version of the dependency, in order to exclude the newer dependency. My testIntegration block above is tranformed thusly:

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

So, the quick summary of how this works in the Gradle build is:

  1. Create a configuration which extendsFrom the main configuration (eg compile ), then use ResolutionStrategy#force and ResolutionStrategy#forcedModules to add the earlier version of the dependency to that configuration's dependency list.
  2. Create a second configuration which does not extend from anything, intended to hold the newer version of the dependency.
  3. In sourceSets , append the configuration created in Step 1 to the compileClasspath and runtimeClasspath for the target where you wish to force the earlier dependency version.
  4. In dependencies , add the newer version of the artifact as a dependency for the configuration created in Step 2.
  5. The classpath in the target block now contains the union of the default dependencies plus the earlier version, as a result of the actions taken in Steps 1 and 3. To remove the newer version, set classpath to classpath.minus(newerDependencyConfiguration) , where newerDependencyConfiguration is the one created in Step 2.

I was facing the same problem but simpler version. cause I am not differentiate the integration test and unit test. using this seems give the right guava dependency for 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'
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM