Publish test class jars independently from main jar

RE: gradle 5.6.4

I have a Java library that has a utility API that includes utilities for unit testing. I want to publish two separate artifacts to maven, one for the utility API and one for the unit test utility API. I’ve defined the following task for jar’ing the test classes:

task testJar(type: Jar, dependsOn: testClasses) {
  archiveClassifier 'tests'
  from sourceSets.test.output
}

I then have the following maven publishing declaration:

publishing {
  ...

  publications {
    mavenJava(MavenPublication) {
      // publish main jar
      ...
    }

    mavenJava(MavenPublication) {
      groupId project.group
      artifactId "${project.name}-tests"
      version project.version

      artifact testJar
    }

This works in that two distinct artifacts are published to maven, but, the second artifact with artifactId '${project.name}-tests' includes BOTH the -tests.jar with the test classes AND the regular main classes jar. I’m not sure that this is actually going to create a problem for projects that are dependent on this artifact, but I’d prefer to exclude the main classes jar if possible. Does anyone know if I can do this? I’m not sure how/why the jar is automagically being included in the first place if I’m not calling from components.java. I’ve tried experimenting with a few different variants in this mavenJava publication block, but the results are always the same. Any guidance would be appreciated.

The code snippet is not correctly creating two separate publications. Rename one of the publications from mavenJava to a different name. Once you do that you will no longer need to set archiveClassifier and the test jar can be published as the main artifact of the <project name>-test module.

IMO Gradle should fail when you try to create two publications with the same name, but I guess there could be a bug somewhere.

Chris, thank you very much for your reply. I didn’t realize that the mavenJava declaration could take different names. I’m not terribly familiar with the gradle DSL or its “parts of speech”. That said, by creating two publications with different names, I was indeed able to solve my problem.

I have tried below code but its still not publishing code from my base project including testImplementation dependancies available in my build.gradle file. I am trying to achieve reusability and avoid code duplication using this approach so other dependent project can use existing code and testImplementation dependencies from my base project by adding jar in their project.

task sourcesTestJar(type: Jar,  dependsOn: testClasses) {
    from sourceSets.test.allSource
    from sourceSets.test.output
    archiveClassifier.set('test-sources')
    duplicatesStrategy = DuplicatesStrategy.INCLUDE
}



configurations {
    testImplementation.extendsFrom implementation
}

publishing {
    publications {
        mavenJava(MavenPublication) {
            from components.java

            // Specify your groupId, artifactId, and version
            groupId = 'com.yourcompany'
            artifactId = 'basemain-project'
            version = '5.0.0-SNAPSHOT'
        }

         mavenTest(MavenPublication) {

            artifact sourcesTestJar
            // Specify your groupId, artifactId, and version
            groupId = 'com.yourcompany'
            artifactId = 'basetest-project'
            version = '5.0.0-SNAPSHOT'
        }

    }
    repositories {
        maven {
            url 'https://pkgs.dev.azure.com/{$company}/_packaging/{$project}/maven/v1'
            credentials {
                username = ""
                password = ""
            }
        }
    }
}

Are you sure you want to share the test source code and not some binary test utilities/fixtures? With modern versions of Gradle you can use the java test fixtures plugin to compile, publish, and consume these types of test helpers.

As for why you get no dependencies with the mavenTest publication, the dependencies in mavenJava are coming from the java component. You could define your own custom component and use the dependency configurations to attach the required deps.