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.
build.gradle
: (may vary based on legacy syntax/vs not + gradle version)
- Add the shadow plugin:
buildscript {
repositories {
maven {
url "https://plugins.gradle.org/m2/"
}
}
dependencies {
classpath "gradle.plugin.com.github.johnrengelman:shadow:7.1.2"
}
}
- Add the
junit-platform-console-standalone
dependency:
dependencies {
testImplementation 'org.junit.platform:junit-platform-console-standalone:1.8.2'
}
- 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"
}
}
- 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
- 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
)
- Party 🎉 🦄 🚀
spring gradle shadowJar SpringBootTest JUnit ConsoleLauncher "@SpringBootTest without gradle and JUnit" "SpringBootTest from shadowJar"