4

I maintain at least 2 Java Gradle projects. Let's say that I have a common project named A and another project B that depends on A. A is technically common to many other projects, but that isn't a minor detail to my problem. Anyways, the current situation is that B declares a dependency on A as a plain-old external dependency in its build.gradle file, like so:

compile group:'com.example', name: 'A', version: '0.1'

We have code specific to tests in A that we share with B by placing it in src/main/java. This code has to stay in A instead of B because there are other projects depending on A that use this test code. I'd like to avoid putting the code in this directory because it has no purpose being deployed to production, due to its test-only nature. Also, simply moving the code from A to B wouldn't be possible because other projects in my organization depend on the same code and I want to avoid code duplication. I would rather move this test code in A to src/test/java, but then it won't be published to A's JAR file.

Thus, I am trying to pursue a solution where this code lives in src/test/java in A and is deployed in a test-only JAR file. There are posts that discuss possible solutions, such as this blog post or SOF posts such as Multi-project test dependencies with gradle and Multi-project test dependencies with gradle. HOWEVER, I continuous run into a problem caused by the fact that I am not maintaining a multi-project Gradle build, but rather two completely separate single-project Gradle builds, and this cannot change.

Where I am at right now is that I am configuring build.gradle for A in the exact way suggested in the blog post, like so:

configurations {
    testOutput.extendsFrom testCompile
}

task jarTest (type: Jar, dependsOn: testClasses) {
    from sourceSets.test.output
    classifier = 'test'
}

artifacts {
    testOutput jarTest
}

And then I have A declared as both compile and testCompile dependencies in build.gradle of B:

compile(group: 'com.example', name: 'A', version: '0.1')
testCompile(group: 'com.example', name: 'A', version: '0.1', configuration: 'testOutput')

This doesn't work. I am not getting any of the testCompile dependencies visible in the test classpath for B; these testCompile dependencies are not being reported by gradle dependencies nor are recognized by my IDE's code search (IntelliJ). I threw up a Hail Mary and even tried to replace configuration: 'testOutput' with classifier: 'test', but to no avail. Gradle documentation doesn't quite seem to help either, as it seems that my use case isn't really covered in their intended use cases.

Any way I can achieve my desired usage of Gradle, or am I stuck with exporting test-only code in the main JAR file of A? All help much appreciated.

Community
  • 1
  • 1
ecbrodie
  • 11,246
  • 21
  • 71
  • 120
  • Can you confirm whether you're actually publishing the test artifacts as well as the normal artifacts? – Oliver Charlesworth Nov 03 '15 at 21:53
  • What's the best way to do this? I tried to look at my gradle cache in `~/.gradle`, but it looks like this directory isn't organized in the easiest manner to navigate. Do I need to configure a publish to local Maven repo instead? Or any other advice? – ecbrodie Nov 03 '15 at 22:41

1 Answers1

0

I would treat code that is only needed during testing exactly the same as libraries that are only used during testing (e.g. JUnit or Mockito): The code should be in a separate module with its own name.

So I suggest that you split A into two modules (of the same multi-project build):

  • A
  • A-test-support

The dependencies of A would have to change to:

dependencies {
    testCompile project(':A-test-support')
}

In B you have to use these dependencies:

dependencies {
    compile(group: 'com.example', name: 'A', version: '0.1')
    testCompile(group: 'com.example', name: 'A-test-support', version: '0.1')
}
Johan Stuyts
  • 3,607
  • 1
  • 18
  • 21