如何在 Gradle/Spring Boot/Kotlin 应用程序中为单元、集成和端到端测试创建不同的文件夹?

Luc*_*ues 2 gradle kotlin spring-boot junit5 spring-kafka

我有一个使用 Spring Boot、Gradle 和 Kotlin 构建的应用程序,它与 Kafka 和 PostgreSQL 连接。我正在使用它resources/application.yml作为配置文件。\n我想为每种测试创建一个特定的包:单元、集成和端到端,但现在我有一个仅用于单元测试的包。做这个的最好方式是什么?我正在使用 Junit5。

\n

我想要这样的东西:

\n
application/\n\xe2\x94\x9c\xe2\x94\x80 src/\n\xe2\x94\x82  \xe2\x94\x9c\xe2\x94\x80 e2e/\n\xe2\x94\x82  \xe2\x94\x9c\xe2\x94\x80 integration/\n\xe2\x94\x82  \xe2\x94\x9c\xe2\x94\x80 main/\n\xe2\x94\x82  \xe2\x94\x9c\xe2\x94\x80 test/\nbuild.gradle.kts\ngradlew\ngradlew.properties\nsettings.gradle.kts\n
Run Code Online (Sandbox Code Playgroud)\n

另外,我希望在运行单元测试时我的应用程序不要连接到 Kafka 或 Postgres,但在运行集成测试时我希望它这样做。我怎样才能做到这一点?

\n

我尝试了 Kafka 的配置,但没有成功:

\n
application/\n\xe2\x94\x9c\xe2\x94\x80 src/\n\xe2\x94\x82  \xe2\x94\x9c\xe2\x94\x80 e2e/\n\xe2\x94\x82  \xe2\x94\x9c\xe2\x94\x80 integration/\n\xe2\x94\x82  \xe2\x94\x9c\xe2\x94\x80 main/\n\xe2\x94\x82  \xe2\x94\x9c\xe2\x94\x80 test/\nbuild.gradle.kts\ngradlew\ngradlew.properties\nsettings.gradle.kts\n
Run Code Online (Sandbox Code Playgroud)\n

我还创建了一个注释来模拟所有 Kafka 消费者和生产者(这有效,但我不想在每个测试类中添加此注释)

\n
spring\n    autoconfigure:\n        exclude: org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration\n
Run Code Online (Sandbox Code Playgroud)\n

我的消费者看起来像这样:

\n
@MockBeans(MockBean(MyConsumer::class), MockBean(MyProducer::class))\nannotation class MockKafka\n\n@SpringBootTest\n@MockKafka\nclass MyAwesomeTest { // tests here }\n
Run Code Online (Sandbox Code Playgroud)\n

我的 application.yaml 文件如下所示:

\n
@Component\nclass MyConsumer() {\n    private val logger = LoggerFactory.getLogger(this.javaClass)\n\n    @RetryableTopic(\n        attempts = "\\${kafka-config.consumer.properties.retry.attempts}",\n        backoff = Backoff(delayExpression = "\\${kafka-config.consumer.properties.retry.delay}"),\n        fixedDelayTopicStrategy = FixedDelayStrategy.SINGLE_TOPIC\n    )\n    @KafkaListener(\n        topics = ["\\${spring.kafka.topic.my-topic}"],\n        groupId = "\\${spring.kafka.group-id}"\n    )\n    fun consumer(event: MyEvent) { // logic here }\n}\n
Run Code Online (Sandbox Code Playgroud)\n
Kotlin version: 1.5.0\nSpring Boot version: 2.4.6\nGradlew version: 7.0.2\n
Run Code Online (Sandbox Code Playgroud)\n

提前致谢!

\n

Che*_*Liu 5

不同测试的单独文件夹

\n

事实上,Gradle 在官方指南中确实描述了如何实现这一点。这是您的案例的示例build.gradle.kts

\n
plugins {\n    kotlin("jvm") version "1.5.0"\n\n    id("org.springframework.boot") version "2.5.2"\n    id("io.spring.dependency-management") version "1.0.11.RELEASE"\n}\n\ngroup = "com.example.app"\nversion = "0.1.0-SNAPSHOT"\n\nrepositories {\n    mavenCentral()\n}\n\nsourceSets {\n    create("intTest") {\n        compileClasspath += sourceSets.main.get().output\n        runtimeClasspath += sourceSets.main.get().output\n    }\n    create("e2eTest") {\n        compileClasspath += sourceSets.main.get().output\n        runtimeClasspath += sourceSets.main.get().output\n    }\n}\n\nval intTestImplementation: Configuration by configurations.getting {\n    extendsFrom(configurations.implementation.get())\n}\n\nval e2eTestImplementation: Configuration by configurations.getting {\n    extendsFrom(configurations.implementation.get())\n}\n\nconfigurations["intTestImplementation"].extendsFrom(configurations.runtimeOnly.get())\nconfigurations["e2eTestImplementation"].extendsFrom(configurations.runtimeOnly.get())\n\ndependencies {\n    implementation(platform("org.jetbrains.kotlin:kotlin-bom"))\n    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")\n    implementation("org.springframework.boot:spring-boot-starter-web")\n\n    testImplementation(platform("org.junit:junit-bom:5.7.2"))\n    testImplementation("org.junit.jupiter:junit-jupiter")\n    testImplementation("org.springframework.boot:spring-boot-starter-test")\n\n    intTestImplementation(platform("org.junit:junit-bom:5.7.2"))\n    intTestImplementation("org.junit.jupiter:junit-jupiter")\n    intTestImplementation("org.springframework.boot:spring-boot-starter-test")\n\n    e2eTestImplementation(platform("org.junit:junit-bom:5.7.2"))\n    e2eTestImplementation("org.junit.jupiter:junit-jupiter")\n    e2eTestImplementation("org.springframework.boot:spring-boot-starter-test")\n}\n\nval integrationTest = task<Test>("integrationTest") {\n    description = "Runs integration tests."\n    group = "verification"\n\n    testClassesDirs = sourceSets["intTest"].output.classesDirs\n    classpath = sourceSets["intTest"].runtimeClasspath\n    shouldRunAfter("test")\n}\n\nval end2endTest = task<Test>("end2endTest") {\n    description = "Runs end-to-end tests."\n    group = "verification"\n\n    testClassesDirs = sourceSets["e2eTest"].output.classesDirs\n    classpath = sourceSets["e2eTest"].runtimeClasspath\n    shouldRunAfter("test")\n}\n\ntasks.test {\n    useJUnitPlatform()\n}\n\ntasks.getByName<Test>("integrationTest") {\n    useJUnitPlatform()\n}\n\ntasks.getByName<Test>("end2endTest") {\n    useJUnitPlatform()\n}\n\ntasks.check {\n    dependsOn(integrationTest)\n    dependsOn(end2endTest)\n}\n
Run Code Online (Sandbox Code Playgroud)\n

现在文件夹结构可能是这样的:

\n
\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 src\n    \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 e2eTest\n    \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 kotlin\n    \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 com/example/app/controller\n    \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0     \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 HelloControllerE2ETest.kt\n    \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 resources\n    \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 intTest\n    \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 kotlin\n    \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 com/example/app/controller\n    \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0     \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 HelloControllerIntTest.kt\n    \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 resources\n    \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 main\n    \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 kotlin\n    \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 com/example/app\n    \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0     \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 controller/HelloController.kt\n    \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0     \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 App.kt\n    \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 resources\n    \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 test\n        \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 kotlin\n        \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 com/example/app/controller\n        \xe2\x94\x82       \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 HelloControllerTest.kt\n        \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 resources\n
Run Code Online (Sandbox Code Playgroud)\n

不同测试的分离操作

\n

我不熟悉 Kafka,但在我自己的项目中,我对不同 PostgreSQL 设置的每个测试应用了不同的 Spring 配置文件。

\n

首先,为每种测试分配配置文件build.gradle.kts

\n
\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 src\n    \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 e2eTest\n    \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 kotlin\n    \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 com/example/app/controller\n    \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0     \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 HelloControllerE2ETest.kt\n    \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 resources\n    \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 intTest\n    \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 kotlin\n    \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 com/example/app/controller\n    \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0     \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 HelloControllerIntTest.kt\n    \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 resources\n    \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 main\n    \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 kotlin\n    \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 com/example/app\n    \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0     \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 controller/HelloController.kt\n    \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0     \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 App.kt\n    \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 resources\n    \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 test\n        \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 kotlin\n        \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 com/example/app/controller\n        \xe2\x94\x82       \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 HelloControllerTest.kt\n        \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 resources\n
Run Code Online (Sandbox Code Playgroud)\n

然后,创建特定于配置文件的应用程序配置文件到其相应的resources/config

\n
\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 src\n    \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 e2eTest\n    \xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 kotlin\n    \xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 resources/config\n    \xe2\x94\x82\xc2\xa0\xc2\xa0         \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 application-e2e.yml\n    \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 intTest\n    \xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 kotlin\n    \xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 resources/config\n    \xe2\x94\x82\xc2\xa0\xc2\xa0         \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 application-integration.yml\n    \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 main\n    \xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 kotlin\n    \xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 resources/config\n    \xe2\x94\x82\xc2\xa0\xc2\xa0         \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 application.yml\n    \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 test\n        \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 kotlin\n        \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 resources/config\n                \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 application-test.yml\n
Run Code Online (Sandbox Code Playgroud)\n

应用程序将按以下方式加载配置:

\n
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n
命令轮廓配置加载顺序
./gradlew bootRundefaultapplicaiton.yml( > application-default.yml)
./gradlew testtestapplicaiton.yml>application-test.yml
./gradlew integrationTestintegrationapplicaiton.yml>application-integration.yml
./gradlew end2endTeste2eapplicaiton.yml>application-e2e.yml
\n
\n

现在您应该能够为每个测试配置不同的行为。

\n

参考

\n\n