I have a 'base' project in kotlin which configured with gradle dsl. Inside base I have module 'app' and module 'library'. Module app uses module library. I want to access module library's tests from module app's tests (to be precise library's testUtils package).

app.build gradle file has the line implementation(project(":library")) and like that I can't access library's tests in my main code which is good, but I can't access it from app's tests either.

I've read this question (possible duplicate of this question) where the relevant groovy code is:

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

configurations {
    tests
}

artifacts {
    tests testJar
}

but I couldn't implement it in gradle dsl.

Also I checked this question where the code is:

tasks {
    val sourcesJar by creating(Jar::class) {
        dependsOn(JavaPlugin.CLASSES_TASK_NAME)
        classifier = "sources"
        from(sourceSets["main"].allSource)
    }

    val javadocJar by creating(Jar::class) {
        dependsOn(JavaPlugin.JAVADOC_TASK_NAME)
        classifier = "javadoc"
        from(tasks["javadoc"])
    }

    artifacts {
        add("archives", sourcesJar)
        add("archives", javadocJar)
    }
}

I need somehow to add testImplementation not only with library's source code but with library's tests so that in app's tests I would be able to use library's test packages and in app's source code I wouldn't be able to use library's tests.

Thank you.

Update:

base.build:

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import java.time.Duration

plugins {
    kotlin("jvm") version "1.3.21"
}

allprojects {
    repositories {
        jcenter()
    }
}

subprojects {
    apply(plugin = "kotlin")
    dependencies {
        implementation(kotlin("stdlib-jdk8"))
    }
    tasks.withType<KotlinCompile> {
        kotlinOptions.jvmTarget = "1.8"
    }
    tasks.withType<Test> {
        useJUnitPlatform()

        // Make sure tests don't take over 10 minutes
        timeout.set(Duration.ofMinutes(10))
    }
}

base.settings:

import java.net.URI

rootProject.name = "base"

sourceControl {
    gitRepository(URI("https://github.com/path-to-github.git")) {
        producesModule("path.to.package:primitive-storage-layer")
    }
}

include("library")
include("app")

app.build:

plugins {
    application
}

application {
    mainClassName = "path.to.package.MainKt"
}

val junitVersion = "5.5.0-M1"
val hamkrestVersion = "1.7.0.0"
val mockkVersion = "1.9.3"

dependencies {
    implementation(project(":library"))

    testImplementation("org.junit.jupiter:junit-jupiter-api:$junitVersion")
    testImplementation("org.junit.jupiter:junit-jupiter-params:$junitVersion")
    testImplementation("com.natpryce:hamkrest:$hamkrestVersion")
    testImplementation("io.mockk:mockk:$mockkVersion")

    runtime("org.junit.jupiter:junit-jupiter-engine:$junitVersion")
}

library.build:

val primitiveLibraryVersion = "1.0"
val gsonVersion = "2.8.5"
val junitVersion = "5.5.0-M1"
val mockkVersion = "1.9.3"

dependencies {
    implementation("path.to.package:primitive-storage-layer:$primitiveLibraryVersion")
    implementation("com.google.code.gson:gson:$gsonVersion")

    testImplementation("org.junit.jupiter:junit-jupiter-api:$junitVersion")
    testImplementation("io.mockk:mockk:$mockkVersion")
}

1 Answers

0
Michael Gliwinski On

Although it would be possible to produce an artifact containing tests and then use that from another project, I'd avoid that and instead refactor the test utilities into a separate subproject (something like ${app}-test-kit), putting code into main sourceset, and then depend on that subproject from both app and library testImplementation configurations.

This gives you a cleaner separation and it's more obvious as to what is shared and why.