I\'m using this blog post to configure integration tests for a Spring Boot project, but I\'m pretty stuck on declaring the source sets. I also found this post on StackOverfl
I was finally able to figure it out thanks to some help on the Kotlin Slack channel. First of all I had to upgrade to Gradle version 4.10.2.
For more info have a look at these two pages from Gradle:
Then I just had to create the sourceSets for the integrationTests
sourceSets {
create("integrationTest") {
kotlin.srcDir("src/integrationTest/kotlin")
resources.srcDir("src/integrationTest/resources")
compileClasspath += sourceSets["main"].output + configurations["testRuntimeClasspath"]
runtimeClasspath += output + compileClasspath + sourceSets["test"].runtimeClasspath
}
}
This would work just fine for Java, but since I'm working with Kotlin I had to add an extra withConvention
wrapper
sourceSets {
create("integrationTest") {
withConvention(KotlinSourceSet::class) {
kotlin.srcDir("src/integrationTest/kotlin")
resources.srcDir("src/integrationTest/resources")
compileClasspath += sourceSets["main"].output + configurations["testRuntimeClasspath"]
runtimeClasspath += output + compileClasspath + sourceSets["test"].runtimeClasspath
}
}
}
In the docs they only put runtimeClasspath += output + compileClasspath
, but I added sourceSets["test"].runtimeClasspath
so I can directly use the test dependencies instead of declaring new dependencies for the integrationTest
task.
Once the sourceSets were created it was a matter of declaring a new task
task<Test>("integrationTest") {
description = "Runs the integration tests"
group = "verification"
testClassesDirs = sourceSets["integrationTest"].output.classesDirs
classpath = sourceSets["integrationTest"].runtimeClasspath
mustRunAfter(tasks["test"])
}
After this the tests still didn't run, but that was because I'm using JUnit4. So I just had to add useJUnitPlatform()
which makes this the final code
task<Test>("integrationTest") {
description = "Runs the integration tests"
group = "verification"
testClassesDirs = sourceSets["integrationTest"].output.classesDirs
classpath = sourceSets["integrationTest"].runtimeClasspath
mustRunAfter(tasks["test"])
useJUnitPlatform()
}
Here is git repo that you can refer to: enter link description here
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.gradle.api.tasks.testing.logging.TestLogEvent
plugins {
application
kotlin("jvm") version "1.3.72"
id("com.diffplug.gradle.spotless") version "3.24.2"
id("org.jmailen.kotlinter") version "1.26.0"
checkstyle
}
version = "1.0.2"
group = "org.sample"
application {
mainClass.set("org.sample.MainKt")
}
repositories {
mavenCentral()
jcenter()
}
tasks.checkstyleMain { group = "verification" }
tasks.checkstyleTest { group = "verification" }
spotless {
kotlin {
ktlint()
}
kotlinGradle {
target(fileTree(projectDir).apply {
include("*.gradle.kts")
} + fileTree("src").apply {
include("**/*.gradle.kts")
})
ktlint()
}
}
tasks.withType<Test> {
useJUnitPlatform()
testLogging {
lifecycle {
events = mutableSetOf(TestLogEvent.FAILED, TestLogEvent.PASSED, TestLogEvent.SKIPPED)
exceptionFormat = TestExceptionFormat.FULL
showExceptions = true
showCauses = true
showStackTraces = true
showStandardStreams = true
}
info.events = lifecycle.events
info.exceptionFormat = lifecycle.exceptionFormat
}
val failedTests = mutableListOf<TestDescriptor>()
val skippedTests = mutableListOf<TestDescriptor>()
addTestListener(object : TestListener {
override fun beforeSuite(suite: TestDescriptor) {}
override fun beforeTest(testDescriptor: TestDescriptor) {}
override fun afterTest(testDescriptor: TestDescriptor, result: TestResult) {
when (result.resultType) {
TestResult.ResultType.FAILURE -> failedTests.add(testDescriptor)
TestResult.ResultType.SKIPPED -> skippedTests.add(testDescriptor)
else -> Unit
}
}
override fun afterSuite(suite: TestDescriptor, result: TestResult) {
if (suite.parent == null) { // root suite
logger.lifecycle("----")
logger.lifecycle("Test result: ${result.resultType}")
logger.lifecycle(
"Test summary: ${result.testCount} tests, " +
"${result.successfulTestCount} succeeded, " +
"${result.failedTestCount} failed, " +
"${result.skippedTestCount} skipped")
failedTests.takeIf { it.isNotEmpty() }?.prefixedSummary("\tFailed Tests")
skippedTests.takeIf { it.isNotEmpty() }?.prefixedSummary("\tSkipped Tests:")
}
}
private infix fun List<TestDescriptor>.prefixedSummary(subject: String) {
logger.lifecycle(subject)
forEach { test -> logger.lifecycle("\t\t${test.displayName()}") }
}
private fun TestDescriptor.displayName() = parent?.let { "${it.name} - $name" } ?: "$name"
})
}
dependencies {
implementation(kotlin("stdlib"))
implementation("com.sparkjava:spark-core:2.5.4")
implementation("org.slf4j:slf4j-simple:1.7.30")
testImplementation("com.squareup.okhttp:okhttp:2.5.0")
testImplementation("io.kotest:kotest-runner-junit5-jvm:4.0.5")
testImplementation("io.kotest:kotest-assertions-core-jvm:4.0.5") // for kotest core jvm assertions
testImplementation("io.kotest:kotest-property-jvm:4.0.5")
}
sourceSets {
create("integTest") {
kotlin {
compileClasspath += main.get().output + configurations.testRuntimeClasspath
runtimeClasspath += output + compileClasspath
}
}
}
val integTest = task<Test>("integTest") {
description = "Runs the integTest tests"
group = "verification"
testClassesDirs = sourceSets["integTest"].output.classesDirs
classpath = sourceSets["integTest"].runtimeClasspath
mustRunAfter(tasks["test"])
}
tasks.check {
dependsOn(integTest)
}
sourceSets {
create("journeyTest") {
kotlin {
compileClasspath += main.get().output + configurations.testRuntimeClasspath
runtimeClasspath += output + compileClasspath
}
}
}
val journeyTest = task<Test>("journeyTest") {
description = "Runs the JourneyTest tests"
group = "verification"
testClassesDirs = sourceSets["journeyTest"].output.classesDirs
classpath = sourceSets["journeyTest"].runtimeClasspath
mustRunAfter(tasks["integTest"])
}
tasks.check {
dependsOn(journeyTest)
}
I hope this helps. :)
As of Gradle 5.2.1 see https://docs.gradle.org/current/userguide/java_testing.html#sec:configuring_java_integration_tests
sourceSets {
create("intTest") {
compileClasspath += sourceSets.main.get().output
runtimeClasspath += sourceSets.main.get().output
}
}
val intTestImplementation by configurations.getting {
extendsFrom(configurations.testImplementation.get())
}
configurations["intTestRuntimeOnly"].extendsFrom(configurations.runtimeOnly.get())
dependencies {
intTestImplementation("junit:junit:4.12")
}
val integrationTest = task<Test>("integrationTest") {
description = "Runs integration tests."
group = "verification"
testClassesDirs = sourceSets["intTest"].output.classesDirs
classpath = sourceSets["intTest"].runtimeClasspath
shouldRunAfter("test")
}
tasks.check { dependsOn(integrationTest) }
I didnt like the use of withConvention and how the kotlin src dir was set. So after check out both gradle docs here and here, I came up with this:
sourceSets {
create("integrationTest") {
kotlin {
compileClasspath += main.get().output + configurations.testRuntimeClasspath
runtimeClasspath += output + compileClasspath
}
}
}
val integrationTest = task<Test>("integrationTest") {
description = "Runs the integration tests"
group = "verification"
testClassesDirs = sourceSets["integrationTest"].output.classesDirs
classpath = sourceSets["integrationTest"].runtimeClasspath
mustRunAfter(tasks["test"])
}
tasks.check {
dependsOn(integrationTest)
}
I preferr the less verbose style when using kotlin {
and the use of variable for the new integrationTestTask.