Gradle Test Dependency
Asked Answered
M

9

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?

Motorbus answered 28/2, 2011 at 16:0 Comment(1)
possible duplicate: #5644511Grim
R
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.

Ramify answered 1/3, 2011 at 10:20 Comment(10)
Is there no other way to do this except compile test classes?Halfwit
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.Ramify
for later versions of Gradle (I'm using 1.3) the line "from sourceSets.test.classes" should read "from sourceSets.test.output"Francklyn
There should have been some direct way to do it. This worked great for me nonetheless. Thanks for sharing.Unwonted
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.Wreathe
To pull in all the transitive dependencies of the tests as well, I added: configurations { tests { extendsFrom testRuntime } }Straightedge
How to achieve the same for the androidTest classes?Hesta
not working for me, always get - Could not get unknown property 'testClasses'Georgettegeorgi
@Halfwit ... 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.Dished
Can you add a variant for Kotlin?Bangkok
D
19

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

Danyel answered 18/8, 2015 at 21:45 Comment(1)
This breaks IDE integration and misses transitive dependencies. It also breaks encapsulation of projects, which is always a bad practice.Ghee
F
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

Forest answered 10/2, 2021 at 14:18 Comment(1)
"separate source set" is key here. This should be the answer.Disaccord
K
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")
Kobold answered 30/10, 2012 at 14:7 Comment(0)
O
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
     }
Onerous answered 31/5, 2012 at 14:22 Comment(0)
B
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).

Bencher answered 11/2, 2019 at 23:41 Comment(0)
K
0

For Gradle 1.5

task testJar(type: Jar, dependsOn: testClasses) {
    from sourceSets.test.java
    classifier "tests"
}
Katy answered 23/7, 2015 at 15:54 Comment(0)
R
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')
}
Redbreast answered 1/11, 2016 at 17:33 Comment(0)
D
0
dependencies {    
    testImplementation project(':project_name')
}
Delocalize answered 22/5, 2021 at 3:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.