86

I have two projects, project A and Project B. Both are written in groovy and use gradle as their build system.

Project A requires project B. This holds for both the compile and test code.

How can I configure that the test classes of project A have access to the test classes of project B?

Dr. Simon Harrer
  • 1,954
  • 1
  • 15
  • 26
  • 2
    possible duplicate: http://stackoverflow.com/questions/5644011/multi-project-test-dependencies-with-gradle – Rylander Mar 08 '16 at 17:25

9 Answers9

109

You can expose the test classes via a 'tests' configuration and then define a testCompile dependency on that configuration.

I have this block for all java projects, which jars all test code:

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

configurations {
    tests
}

artifacts {
    tests testJar
}

Then when I have test code I want to access between projects I use

dependencies {
    testCompile project(path: ':aProject', configuration: 'tests')
}

This is for Java; I'm assuming it should work for groovy as well.

David Resnick
  • 4,891
  • 5
  • 38
  • 42
  • Is there no other way to do this except compile test classes? – djangofan Dec 08 '12 at 03:21
  • 1
    If I understand your question then yes, as far as I know you'll need to compile the test classes to use them as dependencies. – David Resnick Dec 31 '12 at 19:47
  • 1
    for later versions of Gradle (I'm using 1.3) the line "from sourceSets.test.classes" should read "from sourceSets.test.output" – Ben Jan 28 '13 at 20:06
  • There should have been some direct way to do it. This worked great for me nonetheless. Thanks for sharing. – kdabir Sep 14 '13 at 08:15
  • This is kinda odd because it requires changing the depending module's configuration. There must be a way to access the classes (output) of the test compilation directly as a dependency. – Giovanni Botta Jan 07 '14 at 22:54
  • 2
    To pull in all the transitive dependencies of the tests as well, I added: `configurations { tests { extendsFrom testRuntime } }` – Ramon Jan 16 '14 at 15:22
  • 3
    How to achieve the same for the androidTest classes? – X-HuMan Jan 15 '17 at 13:08
  • 3
    not working for me, always get - `Could not get unknown property 'testClasses'` – pavle Apr 21 '17 at 11:38
  • 1
    @djangofan ... We made an independent `ProjetnameTestingLibrary` sub-project. Then the testCompile looks like: `` testCompile project( ':ProjectnameTestingLibrary' ...`. Any test helper classes and test resources are build in that sub-project. This builds common test resources (code and data) across several modules to test different aspects of the same feature. Individual (spock) test specs are in the usual place. – will Jun 08 '17 at 05:25
  • Can you add a variant for Kotlin? – emeraldhieu Aug 22 '23 at 07:29
18

This is a simpler solution that doesn't require an intermediate jar file:

dependencies {
  ...
  testCompile project(':aProject').sourceSets.test.output
}

There's more discussion in this question: Multi-project test dependencies with gradle

Community
  • 1
  • 1
Kip
  • 107,154
  • 87
  • 232
  • 265
  • 9
    This breaks IDE integration and misses transitive dependencies. It also breaks encapsulation of projects, which is always a bad practice. – Stefan Oehme Feb 20 '17 at 17:40
11

This is now supported as a first class feature in Gradle (since 5.6)

Modules with java or java-library plugins can also include a java-test-fixtures plugin which exposes helper classes and resources to be consumed with testFixtures helper. Benefit of this approach against artifacts and classifiers are:

  • proper dependency management (implementation/api)
  • nice separation from test code (separate source set)
  • no need to filter out test classes to expose only utilities
  • maintained by Gradle

Example:

:modul:one

modul/one/build.gradle

plugins {
  id "java-library" // or "java"
  id "java-test-fixtures"
}

dependencies {
  testFixturesImplementation("your.jar:dependency:0.0.1")
}

or lazyly just add all dependencies of main implementation configuration:

val testFixturesImplementation by configurations.existing
val implementation by configurations.existing
testFixturesImplementation.get().extendsFrom(implementation.get())

modul/one/src/testFixtures/java/com/example/Helper.java

package com.example;
public class Helper {}

:modul:other

modul/other/build.gradle

plugins {
  id "java" // or "java-library"
}
dependencies {
  testImplementation(testFixtures(project(":modul:one")))
}

modul/other/src/test/java/com/example/other/SomeTest.java

package com.example.other;
import com.example.Helper;
public class SomeTest {
  @Test void f() {
    new Helper(); // used from :modul:one's testFixtures
  }
}

For more info, see the documentation: https://docs.gradle.org/current/userguide/java_testing.html#sec:java_test_fixtures

Dirk Hoffmann
  • 1,444
  • 17
  • 35
8

This works for me (Java)

// use test classes from spring-common as dependency to tests of current module
testCompile files(this.project(':spring-common').sourceSets.test.output)
testCompile files(this.project(':spring-common').sourceSets.test.runtimeClasspath)

// filter dublicated dependency for IDEA export
def isClassesDependency(module) {
     (module instanceof org.gradle.plugins.ide.idea.model.ModuleLibrary) && module.classes.iterator()[0].url.toString().contains(rootProject.name)
}

idea {
      module {
          iml.whenMerged { module ->
              module.dependencies.removeAll(module.dependencies.grep{isClassesDependency(it)})
              module.dependencies*.exported = true
          }
      }
  }
.....  
// and somewhere to include test classes 
testRuntime project(":spring-common")
Michail Nikolaev
  • 3,733
  • 22
  • 18
5

The above solution works, but not for the latest version 1.0-rc3 of Gradle.

     task testJar(type: Jar, dependsOn: testClasses) {
       baseName = "test-${project.archivesBaseName}"

       // in the latest version of Gradle 1.0-rc3
       // sourceSets.test.classes no longer works
       // It has been replaced with 
       // sourceSets.test.output

       from sourceSets.test.output
     }
zwessels
  • 617
  • 1
  • 10
  • 25
5

If ProjectA contains the test code you wish to use in ProjectB and ProjectB wants to use artifacts to include the test code, then ProjectB's build.gradle would look like this:

dependencies {

  testCompile("com.example:projecta:1.0.0-SNAPSHOT:tests")

}

Then you need to add an archives command to the artifacts section in ProjectA's build.gradle:

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

configurations {
    tests
}

artifacts {
    tests testsJar
    archives testsJar
}

jar.finalizedBy(testsJar)

Now when ProjectA's artifacts are published to your artifactory they will include a -tests jar. This -tests jar can then be added as a testCompile dependency for ProjectB (as shown above).

Joman68
  • 2,248
  • 3
  • 34
  • 36
0

For Gradle 1.5

task testJar(type: Jar, dependsOn: testClasses) {
    from sourceSets.test.java
    classifier "tests"
}
Robin Elvin
  • 1,207
  • 12
  • 28
0

For Android on the latest gradle version (I'm currently on 2.14.1) you just need to add the below in Project B to get all the test dependencies from Project A.

dependencies {
  androidTestComplie project(path: ':ProjectA')
}
help-info.de
  • 6,695
  • 16
  • 39
  • 41
santugowda
  • 9
  • 1
  • 2
0
dependencies {    
    testImplementation project(':project_name')
}
San Jaisy
  • 15,327
  • 34
  • 171
  • 290