Cross project test dependencies


(Paul S) #1

As a preface to this question, let me first say that we are complete newbies to Gradle. We’re migrating our Java project from Ant to Gradle, and trying to follow Gradle conventions as much as possible. We’ve got a multi-project/multi-module configuration.

RE: Gradle 2.6, Mac OS X, Java 1.8_45

For simplification purposes, let’s say we have just two projects, let’s call them util and scheduling where scheduling depends on the util project. We have classes in util/src/test upon which class in scheduling/src/test depend. In the scheduling/build.gradle file, we have a the following dependency: “compile project (’:util’)”. However, even with this dependency, Gradle does not seem to automagically resolve the test dependencies across the projects. I’ve tried to follow the solution in this other post, Dependencies defined with project(’:projectname’).sourceSets.test.output are not transitive, but it is not working for me. Specifically, even with the recommended changes in that post, I still encounter compile time failures where test classes in scheduling are failing to compile, because they cannot resolve test classes from util.

The biggest problem I’m having right now is that I have no idea where to even start with debugging this issue. I’m compiling with --debug, I see the compileTestJava for my scheduling project, and I see that it does not include any class or sourcepath reference to my util project’s test classes, but I have no idea why. In reviewing the output, it appears that Gradle is attempting to execute scheduling:compileTestJava before util:testJava, and, again, I have no idea why.

Generally speaking, I’m happy with Gradle when it works, but I’m very frustrated that I do not even begin to understand all the automagic functioning or even how to discover what it does for you automatically. If anyone can at least offer this newbie some advice (e.g. teach a man to fish) on how I can figure out the answer to this question and, in the process, better learn how Gradle works and how to debug problems when everything is not working, I would greatly appreciate it.


(Lance Java) #2

You’ll see the same happening in maven. src/main/java are built into the default artifact (jar) but src/test/java is not. To keep it simple, a dependency is always a jar file so you’ll need these test util classes to be built into a jar to use them in another project. The jar must be registered as a artifact (so that it can be published / discovered).

This can be done in two different ways:

  1. Create another project for the test utilities with its own artifact id
  2. Build a “test” artifact in within the same project. This will likely have a “test” classifier and will need to be registered as an artifact explicitly

Once you have this jar, you’ll be able to add it to your test classpath without it being on the production classpath.


(Sterling Greene) #3

The other important part is you should produce this as a separate configuration, like is described here.


(Paul S) #4

Thanks so much for the replies. I’m not sure if you happened to look, but the example I referenced is trying to build a jar and create a configuration, but that’s not working for me. By trial and error, and scanning the output, I’ve figured out how to see what tasks are being executed. If I do just a simple ./gradlew clean :util:build, the testJar task is never run, even though tests are compiled and run. Again, I have no idea how to even begin to troubleshoot this. Here is my entire util/build.gradle file (retyped by hand, so apologies for any typos). Also, note that everything works fine from the IDEA 14 IDE. The problems we’re having are from command line builds using Grade.

dependencies {
testCompile ‘com.google.http-client:google-http-client:1.20.0’
}

configurations {
tests.extendsFrom testRuntime
}

task testJar(type: Jar, dependsOn: testClasses) {
baseName ='test-${project.archiveBaseName}
from sourceSets.test.output
}

artifacts {
tests testJar
}


(Paul S) #5

I’m starting to fumble my way through this. For others following a similar Ant-Gradle path, my comment would be to be very patient. Whereas a relatively small toolkit of Ant knowledge will take you very far, Gradle seems to require a much deeper understanding to do what would be simple tasks in Ant.

So, the issue I was having with getting the test jar to build is that the java plug-in doesn’t have any automagic dependencies on my newly created tests configuration. As such, calling ./gradlew :util:build isn’t going to cause the testJar task to be run. However, by adding the testCompile project(path: ‘:util’, configuration: ‘tests’) to the scheduling/build.gradle file, when you run ./graldew :scheduling:build, it will invoke that testJar task.

One helpful aspect I just discovered is that Gradle seems to handle transitive dependencies of this sort quite nicely. That is to say, if I have another subproject called transportation that depends on scheduling, it seems that I need to add only the one testCompile dependency to transportation/build.gradle that references scheduling, and Gradle automatically includes the util test class dependency in the transportation test build.

In any event, I feel a little less lost now than I did before, so thanks to everyone for the help!


(Lance Java) #6

On a related note, Netflix have deprecated their nebula.test-jar plugin here as “we feel it is better to create a project for any shared test harnesses than to try and create an extra jar…”

If you still want to do it, either use the nebula plugin or copy the code here