与Gradle Kotlin DSL的集成测试
我正在使用为Spring Boot项目配置集成测试,但我在声明源代码集时遇到了很大困难。我也发现了,但我想我已经有点远了 我的项目结构是与Gradle Kotlin DSL的集成测试,gradle,kotlin,integration-testing,gradle-kotlin-dsl,Gradle,Kotlin,Integration Testing,Gradle Kotlin Dsl,我正在使用为Spring Boot项目配置集成测试,但我在声明源代码集时遇到了很大困难。我也发现了,但我想我已经有点远了 我的项目结构是 project |_ src |_ main | |_ kotlin | |_ resources |_ testIntegration | |_ kotlin | |_ resources |_ test | |_ kotlin | |_ resources |_ build.gradle.kts |_ ... o
project
|_ src
|_ main
| |_ kotlin
| |_ resources
|_ testIntegration
| |_ kotlin
| |_ resources
|_ test
| |_ kotlin
| |_ resources
|_ build.gradle.kts
|_ ... other files
和build.gradle.kts
我想我的方向是对的。至少它不再抛出异常:)
当我运行testIntegration任务时,我得到以下输出:
Testing started at 12:08 ...
12:08:49: Executing task 'testIntegration'...
> Task :project:compileKotlin UP-TO-DATE
> Task :project:compileJava NO-SOURCE
> Task :project:processResources UP-TO-DATE
> Task :project:classes UP-TO-DATE
> Task :project:compileTestKotlin UP-TO-DATE
> Task :project:compileTestJava NO-SOURCE
> Task :project:processTestResources UP-TO-DATE
> Task :project:testClasses UP-TO-DATE
> Task :project:testIntegration
BUILD SUCCESSFUL in 2s
5 actionable tasks: 1 executed, 4 up-to-date
12:08:51: Task execution finished 'testIntegration'.
此外,IntelliJ不将testIntegration目录识别为Kotlin软件包。多亏了Kotlin Slack频道上的一些帮助,我终于能够找到它。首先,我必须升级到Gradle版本4.10.2 有关更多信息,请查看Gradle的以下两页:
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
}
}
这对于Java来说很好,但是因为我在使用Kotlin,所以我不得不添加一个额外的withConvention
包装器
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
}
}
}
在文档中,他们只放置runtimeClasspath+=output+compileClasspath
,但我添加了sourceset[“test”]。runtimeClasspath
,因此我可以直接使用测试依赖项,而不是为integrationTest
任务声明新的依赖项
一旦创建了源集,就需要声明一个新任务
task<Test>("integrationTest") {
description = "Runs the integration tests"
group = "verification"
testClassesDirs = sourceSets["integrationTest"].output.classesDirs
classpath = sourceSets["integrationTest"].runtimeClasspath
mustRunAfter(tasks["test"])
}
自Gradle 5.2.1起,见
sourceset{
创建(“intTest”){
compileClasspath+=sourceset.main.get().output
runtimeClasspath+=sourceSets.main.get().output
}
}
val IntTest按配置实现。获取{
ExtendFrom(configurations.testImplementation.get())
}
配置[“intTestRuntimeOnly”].ExtendFrom(configurations.runtimeOnly.get())
依赖关系{
intTestImplementation(“junit:junit:4.12”)
}
val集成测试=任务(“集成测试”){
description=“运行集成测试。”
group=“验证”
testClassesDirs=sourceSets[“intTest”].output.classesDirs
类路径=源集[“intTest”]。运行时类路径
应在“测试”之后运行
}
tasks.check{dependsOn(integrationTest)}
我不喜欢使用withConvention和kotlin src dir的设置方式。所以在查看了gradle和docs之后,我想到了这个:
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)
}
sourceset{
创建(“集成测试”){
科特林{
compileClasspath+=main.get().output+configurations.testRuntimeClasspath
runtimeClasspath+=output+compileClasspath
}
}
}
val集成测试=任务(“集成测试”){
description=“运行集成测试”
group=“验证”
testClassesDirs=sourceSets[“integrationTest”].output.classesDirs
classpath=sourceSets[“integrationTest”]。运行时类路径
mustRunAfter(任务[“测试”])
}
任务。检查{
dependsOn(集成测试)
}
我更喜欢在使用
kotlin{
时使用不太详细的样式,以及在新的integrationTestTask中使用变量。以下是git repo,您可以参考:
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
导入org.gradle.api.tasks.testing.logging.TestLogEvent
插件{
应用
kotlin(“jvm”)版本“1.3.72”
id(“com.diffplug.gradle.spotless”)版本“3.24.2”
id(“org.jmailen.kotlinter”)版本“1.26.0”
代码检查
}
version=“1.0.2”
group=“org.sample”
应用{
mainClass.set(“org.sample.MainKt”)
}
存储库{
mavenCentral()
jcenter()
}
tasks.checkstyleMain{group=“verification”}
tasks.checkstyleTest{group=“verification”}
一尘不染{
科特林{
ktlint()
}
科特林格勒{
目标(fileTree(projectDir).apply{
包括(“*.gradle.kts”)
}+文件树(“src”)。应用{
包括(“***.gradle.kts”)
})
ktlint()
}
}
tasks.withType{
useJUnitPlatform()
测试记录{
生命周期{
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()
val skippedTests=mutableListOf()
addTestListener(对象:TestListener{
重写fun beforeSuite(套件:TestDescriptor){}
重写fun beforeTest(testDescriptor:testDescriptor){}
重写后测试(testDescriptor:testDescriptor,结果:TestResult){
何时(result.resultType){
TestResult.ResultType.FAILURE->failedTests.add(testDescriptor)
TestResult.ResultType.SKIPPED->skippedTests.add(testDescriptor)
其他->单位
}
}
重写fun afterSuite(套件:TestDescriptor,结果:TestResult){
如果(suite.parent==null){//root-suite
logger.lifecycle(“---”)
logger.lifecycle(“测试结果:${result.resultType}”)
logger.lifecycle(
测试摘要:${result.testCount}个测试+
${result.successfulTestCount}成功+
${result.failedTestCount}失败+
“${result.skippedTestCount}跳过”)
failedTests.takeIf{it.isNotEmpty()}?.prefixedSummary(“\t失败的测试”)
skippedTests.takeIf{it.isNotEmpty()}?.prefixedSummary(“\tSkipped Tests:”)
}
}
私有中缀乐趣列表。前缀摘要(主题:字符串){
logger.lifecycle(主题)
forEach{test->logger.lifecycle(“\t\t${test.displayName()”)}
}
private fun TestDescriptor.displayName()=parent?让{“${it.name}-$name”}?:“$name”
})
}
依赖关系{
task<Test>("integrationTest") {
description = "Runs the integration tests"
group = "verification"
testClassesDirs = sourceSets["integrationTest"].output.classesDirs
classpath = sourceSets["integrationTest"].runtimeClasspath
mustRunAfter(tasks["test"])
useJUnitPlatform()
}
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) }
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)
}
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)
}