Warm tip: This article is reproduced from serverfault.com, please click

其他-Spring Boot + Liquibase + Gradle + Testcontainers /找不到配置

(其他 - Spring Boot + Liquibase + Gradle + Testcontainers / Can't find config)

发布于 2020-11-28 15:48:53

因此,我一直在尝试从Maven迁移到Gradle,但现在遇到了一个严重的问题,似乎无法解决。

我基本上只是想为我的测试运行一些简单的liquibase迁移,为此我增加了两个测试容器。一个用于rabbitmqexchange,一个用于postgres DB。

我已经使用这里描述的一些替代方法设置了postgres容器:使用Kotlin和Testcontainers测试Spring Boot应用程序

我已经尝试了上千种方法并搜索了所有相关问题,但是我似乎无法弄清楚问题是什么...

这是使用Gradle 6.7.1进行的设置:

build.gradle.kts

plugins {
    id("org.springframework.boot") version "2.4.0"
    id("io.spring.dependency-management") version "1.0.10.RELEASE"
    application
    kotlin("jvm") version "1.4.20"
    id("org.jetbrains.kotlin.plugin.spring") version "1.4.20"
    id("org.liquibase.gradle") version "2.0.4"
}

repositories {
    mavenLocal()
    mavenCentral()
}

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-web")
    implementation("org.springframework.boot:spring-boot-starter-data-jpa")
    implementation("org.springframework.cloud:spring-cloud-stream:3.0.9.RELEASE")
    implementation("org.springframework.cloud:spring-cloud-stream-binder-rabbit:3.0.9.RELEASE")
    implementation("org.springframework.boot:spring-boot-starter-actuator")
    implementation("org.springframework.boot:spring-boot-configuration-processor")
    implementation("org.liquibase:liquibase-core:4.0.0")
//    liquibaseRuntime("org.liquibase:liquibase-core:4.0.0")
    runtimeOnly("org.postgresql:postgresql:42.2.18")
    testImplementation("org.springframework.boot:spring-boot-starter-test")
    testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.0")
    testImplementation("org.junit.jupiter:junit-jupiter-params:5.7.0")
    testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.7.0")
    testImplementation("org.testcontainers:testcontainers:1.15.0")
    testImplementation("org.testcontainers:junit-jupiter:1.15.0")
    testImplementation("org.testcontainers:rabbitmq:1.15.0")
    testImplementation("org.testcontainers:postgresql:1.15.0")
}

description = "my-project"
java.sourceCompatibility = JavaVersion.VERSION_1_8

application {
    mainClass.set("path/to/the/main/class")
}

tasks.named<Test>("test") {
    useJUnitPlatform()
}

tasks.withType<KotlinCompile> {
    kotlinOptions.jvmTarget = "1.8"
}

tasks.register<Copy>("copyJarToTargetDir") {
    mustRunAfter("build")
    val outputJar = "$buildDir/libs"
    val targetDir = "$projectDir/target"
    from(outputJar)
    include("*.jar")
    into(targetDir)
}

tasks.register<Delete>("deleteTargetDir") {
    mustRunAfter("clean")
    delete("$projectDir/target")
}

tasks.named("build") {
    finalizedBy("copyJarToTargetDir")
}

tasks.named("clean") {
    finalizedBy("deleteTargetDir")
}

基础测试:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles("test")
@Testcontainers
class PartnerEdgeServiceApplicationBaseTests {

    @Autowired
    lateinit var vehicleRepository: VehicleRepository

    @Autowired
    lateinit var vehicleStreamChannel: VehicleDataChannel

    @LocalServerPort
    private val port: Int = 0

    @Test
    fun `check application`() {
        println("Howdy, Partners!")
    }
}

以及相关的测试:

class MessageSinkTest : ApplicationBaseTests() {

    companion object {
        @Container
        val rabbitMQContainer = RabbitMQContainer("rabbitmq:alpine")
        @Container
        val postgresContainer: KPostgreSQLContainer = KPostgreSQLContainer("postgres:10.11-alpine")

        @JvmStatic
        @DynamicPropertySource
        fun properties(registry: DynamicPropertyRegistry) {
            registry.add("spring.datasource.url", postgresContainer::getJdbcUrl)
            registry.add("spring.datasource.password", postgresContainer::getPassword)
            registry.add("spring.datasource.username", postgresContainer::getUsername)
            registry.add("spring.rabbitmq.addresses", rabbitMQContainer::getAmqpUrl)
            registry.add("spring.rabbitmq.username", rabbitMQContainer::getAdminUsername)
            registry.add("spring.rabbitmq.password", rabbitMQContainer::getAdminPassword)
            registry.add("spring.liquibase.url", postgresContainer::getJdbcUrl)
            registry.add("spring.liquibase.user", postgresContainer::getUsername)
            registry.add("spring.liquibase.password", postgresContainer::getPassword)
        }
    }

    @Test
    @DisplayName("Should extract the vehicle data and persist in the DB")
    fun test1() {
        val id = "id"
        val locationId = 1L
        val numberPlate = "Some plate"
        val buildSeries = "VW_TIGUAN"
        val fuel = 75
        val fuelType = "GASOLINE"

        vehicleStreamChannel.input().send(
            GenericMessage(
                VehicleDataStreamDto(
                    id = id,
                    locationId = locationId,
                    numberPlate = numberPlate,
                    buildSeries = buildSeries,
                    fuel = fuel,
                    fuelType = fuelType
                )
            )
        )

        val persistedVehicle = vehicleRepository.findByIdOrNull(vin)
        assertEquals(id, persistedVehicle?.id)
    }
}

和application.yml:

server:
  servlet:
    context-path: /my-project
streaming:
  retries: 5
  concurrency: 15
  amqpGroupName: my_project
spring:
  jpa:
    hibernate:
      ddl-auto: none
    database-platform: org.hibernate.dialect.PostgreSQL94Dialect
  liquibase:
    url: ${spring.datasoure.url}
    user: ${spring.datasource.username}
    password: ${spring.datasoure.password}
    contexts: environment-name-will-be-placed-here
    change-log: classpath:/db/changelog/db.changelog-master.xml
  datasource:
    driver-class-name: org.postgresql.Driver
  cloud:
    stream:
      rabbit:
        bindings:
          vehiclestream:
            consumer:
              declareExchange: true
---
spring:
  jpa:
    database-platform: org.hibernate.dialect.PostgreSQL94Dialect
    hibernate:
      ddl-auto: none
  config:
    activate:
      on-profile: local

运行测试时,我得到以下日志:

Failed to load ApplicationContext
java.lang.IllegalStateException: Failed to load ApplicationContext
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:132)
    at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:123)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:118)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83)
    at org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener.prepareTestInstance(SpringBootDependencyInjectionTestExecutionListener.java:43)
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:244)
    at org.springframework.test.context.junit.jupiter.SpringExtension.postProcessTestInstance(SpringExtension.java:99)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$6(ClassBasedTestDescriptor.java:350)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.executeAndMaskThrowable(ClassBasedTestDescriptor.java:355)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$7(ClassBasedTestDescriptor.java:350)
    at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
    at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175)
    at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1384)
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
    at java.util.stream.StreamSpliterators$WrappingSpliterator.forEachRemaining(StreamSpliterators.java:313)
    at java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:743)
    at java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:742)
    at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:647)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeTestInstancePostProcessors(ClassBasedTestDescriptor.java:349)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$instantiateAndPostProcessTestInstance$4(ClassBasedTestDescriptor.java:270)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateAndPostProcessTestInstance(ClassBasedTestDescriptor.java:269)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$2(ClassBasedTestDescriptor.java:259)
    at java.util.Optional.orElseGet(Optional.java:267)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$3(ClassBasedTestDescriptor.java:258)
    at org.junit.jupiter.engine.execution.TestInstancesProvider.getTestInstances(TestInstancesProvider.java:31)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$prepare$0(TestMethodTestDescriptor.java:101)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:100)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:65)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$prepare$1(NodeTestTask.java:111)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.prepare(NodeTestTask.java:111)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:79)
    at java.util.ArrayList.forEach(ArrayList.java:1259)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
    at java.util.ArrayList.forEach(ArrayList.java:1259)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:248)
    at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$5(DefaultLauncher.java:211)
    at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:226)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:199)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:132)
    at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:99)
    at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:79)
    at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:75)
    at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
    at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
    at com.sun.proxy.$Proxy2.stop(Unknown Source)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker.stop(TestWorker.java:133)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
    at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
    at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:414)
    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
    at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
    at java.lang.Thread.run(Thread.java:748)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'liquibase' defined in class path resource [org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfiguration$LiquibaseConfiguration.class]: Invocation of init method failed; nested exception is liquibase.exception.ChangeLogParseException: The file classpath:/db/changelog/db.changelog-master.xml was not found in
- a bunch of paths

我的db.changelog-master.xml位于以下位置(从项目的根目录开始):

src/main/resources/db/changelog/db.changelog-master.xml

因此,该错误实际上没有任何意义,或者我缺少了某些东西(显然是这种情况……)。无论如何,非常感谢任何帮助!!

更新:

所以,我做了一点改变。我换了这两个依赖项implementation("org.liquibase:liquibase-core:4.0.0")liquibaseRuntime("org.liquibase:liquibase-core:4.0.0")并删除了jpa.properties我的application.yml上的。我确实收到了另一个错误:

{"@timestamp":"2020-11-29T09:05:08.612+01:00","@version":"1","logmessage":"SQL Error: 0, SQLState: 42P01","logger_name":"org.hibernate.engine.jdbc.spi.SqlExceptionHelper","thread_name":"Test worker","level":"WARN","level_value":30000,"vin":"vin"}
{"@timestamp":"2020-11-29T09:05:08.614+01:00","@version":"1","logmessage":"ERROR: relation \"vehicles\" does not exist\n  Position: 290","logger_name":"org.hibernate.engine.jdbc.spi.SqlExceptionHelper","thread_name":"Test worker","level":"ERROR","level_value":40000,"vin":"vin"}
{"@timestamp":"2020-11-29T09:05:08.617+01:00","@version":"1","logmessage":"HHH000327: Error performing load command","logger_name":"org.hibernate.event.internal.DefaultLoadEventListener","thread_name":"Test worker","level":"INFO","level_value":20000,"stack_trace":"org.hibernate.exception.SQLGrammarException: could not extract ResultSet
Exception thrown while invoking VehicleDataSink#processData[1 args]; nested exception is org.springframework.dao.InvalidDataAccessResourceUsageException: could not extract ResultSet; SQL [n/a]; 
Questioner
MaxPayne
Viewed
11
MaxPayne 2020-11-30 01:59:28

因此,以供将来参考:该问题与gradle / liquibase无关。这是简单的事实,我创建的目录db/changelog中的一个步骤的IntelliJ,它创建了一个目录db.changelog,而不是/changelog成为的孩子db将其拆分为两个单独的步骤后,一切工作正常!