Skip to content

Instantly share code, notes, and snippets.

@mindstorms6
Last active June 18, 2022 02:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mindstorms6/d10edcacfa80670155689558480334be to your computer and use it in GitHub Desktop.
Save mindstorms6/d10edcacfa80670155689558480334be to your computer and use it in GitHub Desktop.
Build an uber-mega-test jar and run your tests on the CLI when using SpringBootTest

What?

Sometimes, you have a strange need to package all of your test classes in to a giant uber mega jar and run the tests in them. The JUnit ConsoleLauncher works a treat - until you want to use spring and some @SpringBootTest annotations.

Contextually, I had a case where I had some @SpringBootTest classes I wanted to run on repeat but without haivng to deal with gradle. There's almost certainly better ways to do this - but sometimes it's fun to do hard things.

Make an uber mega jar

build.gradle: (may vary based on legacy syntax/vs not + gradle version)

  1. Add the shadow plugin:
buildscript { 
  repositories {
        maven {
            url "https://plugins.gradle.org/m2/"
        }
  }
  dependencies {
        classpath "gradle.plugin.com.github.johnrengelman:shadow:7.1.2"

  }
}
  1. Add the junit-platform-console-standalone dependency:
dependencies {
       testImplementation 'org.junit.platform:junit-platform-console-standalone:1.8.2'
}
  1. Add a task to build the jar:
// this task builds a mega uber jar which includes the classes / testImplementation dependencies from the test configuration/closure
// This means all the compilation for the test is done - so we don't have to invoke gradle and download the world when we just want to run a specific test
// The end result being the test run can run fairly quickly - on a tight-ish loop

import com.github.jengelman.gradle.plugins.shadow.transformers.PropertiesFileTransformer
shadowJar {

    dependsOn testClasses
    archiveClassifier = 'uber-tests'
    zip64 true

    manifest {
        attributes 'Implementation-Title': 'Uber Mega Test Jar File',
                'Main-Class': 'org.junit.platform.console.ConsoleLauncher'
    }

    exclude '**/Log4j2Plugins.dat'
    exclude 'META-INF/*.RSA', 'META-INF/*.SF', 'META-INF/*.DSA'
    from sourceSets.main.output
    from sourceSets.test.output
    configurations = [project.configurations.testRuntimeClasspath, project.configurations.runtimeClasspath]
    with jar

    // Required for Spring
    mergeServiceFiles()
    append 'META-INF/spring.handlers'
    append 'META-INF/spring.schemas'
    append 'META-INF/spring.tooling'
    transform(PropertiesFileTransformer) {
        paths = ['META-INF/spring.factories' ]
        mergeStrategy = "append"
    }
}
  1. Run the shadowJar task to produce the finalized mega-jar
./gradlew shadowJar

You should see a jar file in your output directory (usually build/libs) that's something like ${projectName}*-uber-tests.jar

  1. Execute the test/tests you want - from the jar (assume the uber-jar was named myservice-uber-tests.jar)
java -cp ./build/libs/myservice-uber-tests.jar org.junit.platform.console.ConsoleLauncher --scan-classpath -cp ./build/libs/myservice-uber-tests.jar  --fail-if-no-tests

The ConsoleLauncher documetnation has more details on how you can run a specific test/class (eg --include-classname)

  1. Party 🎉 🦄 🚀

SEO

spring gradle shadowJar SpringBootTest JUnit ConsoleLauncher "@SpringBootTest without gradle and JUnit" "SpringBootTest from shadowJar"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment