繁体   English   中英

Spring 使用 liquibase 启动测试失败

[英]Spring boot testing with liquibase fails

我已经尝试了很长时间来找出解决我的问题的方法,但无济于事。

无论如何,我有一堆集成测试(在与标准测试目录平行的非标准目录 testRegression 中)。

这些集成测试在 memory 数据库中使用 h2。 在生产和测试中,我使用 liquibase 来模拟模式演变。

我的属性(在 application-testRegression.properties 中)如下所示:

spring.liquibase.enabled=true
spring.liquibase.user=sa
spring.liquibase.password=
spring.liquibase.change-log=classpath:/liquibase/changelog-master.xml

spring.datasource.url=jdbc:p6spy:h2:mem:testdb;MODE=PostgreSQL;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=FALSE;INIT=CREATE SCHEMA IF NOT EXISTS nmc\\;CREATE SCHEMA IF NOT EXISTS mkt\\;CREATE SCHEMA IF NOT EXISTS cdb\\;CREATE SCHEMA IF NOT EXISTS pg_temp
spring.datasource.driver-class-name=com.p6spy.engine.spy.P6SpyDriver
spring.datasource.username=sa
spring.datasource.password=

我不断得到的错误是:

2020-07-21 15:57:34.173 INFO  [liquibase.lockservice.StandardLockService] [Test worker:13]: Successfully acquired change log lock
2020-07-21 15:57:34.303 INFO  [liquibase.changelog.StandardChangeLogHistoryService] [Test worker:13]: Creating database history table with name: PUBLIC.DATABASECHANGELOG
2020-07-21 15:57:34.305 INFO  [liquibase.executor.jvm.JdbcExecutor] [Test worker:13]: CREATE TABLE PUBLIC.DATABASECHANGELOG (ID VARCHAR(255) NOT NULL, AUTHOR VARCHAR(255) NOT NULL, FILENAME VARCHAR(255) NOT NULL, DATEEXECUTED TIMESTAMP NOT NULL, ORDEREXECUTED INT NOT NULL, EXECTYPE VARCHAR(10) NOT NULL, MD5SUM VARCHAR(35), DESCRIPTION VARCHAR(255), COMMENTS VARCHAR(255), TAG VARCHAR(255), LIQUIBASE VARCHAR(20), CONTEXTS VARCHAR(255), LABELS VARCHAR(255), DEPLOYMENT_ID VARCHAR(10))
2020-07-21 15:57:34.307 INFO  [liquibase.lockservice.StandardLockService] [Test worker:13]: Successfully released change log lock
2020-07-21 15:57:34.309 WARN  [org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext] [Test worker:13]: Exception encountered during context initialization - cancelling refresh attempt: 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.DatabaseException: Table "DATABASECHANGELOG" already exists; SQL statement:
CREATE TABLE PUBLIC.DATABASECHANGELOG (ID VARCHAR(255) NOT NULL, AUTHOR VARCHAR(255) NOT NULL, FILENAME VARCHAR(255) NOT NULL, DATEEXECUTED TIMESTAMP NOT NULL, ORDEREXECUTED INT NOT NULL, EXECTYPE VARCHAR(10) NOT NULL, MD5SUM VARCHAR(35), DESCRIPTION VARCHAR(255), COMMENTS VARCHAR(255), TAG VARCHAR(255), LIQUIBASE VARCHAR(20), CONTEXTS VARCHAR(255), LABELS VARCHAR(255), DEPLOYMENT_ID VARCHAR(10)) [42101-197] [Failed SQL: (42101) CREATE TABLE PUBLIC.DATABASECHANGELOG (ID VARCHAR(255) NOT NULL, AUTHOR VARCHAR(255) NOT NULL, FILENAME VARCHAR(255) NOT NULL, DATEEXECUTED TIMESTAMP NOT NULL, ORDEREXECUTED INT NOT NULL, EXECTYPE VARCHAR(10) NOT NULL, MD5SUM VARCHAR(35), DESCRIPTION VARCHAR(255), COMMENTS VARCHAR(255), TAG VARCHAR(255), LIQUIBASE VARCHAR(20), CONTEXTS VARCHAR(255), LABELS VARCHAR(255), DEPLOYMENT_ID VARCHAR(10))]
2020-07-21 15:57:34.309 INFO  [com.zaxxer.hikari.HikariDataSource] [Test worker:13]: HikariPool-3 - Shutdown initiated...
2020-07-21 15:57:34.324 INFO  [com.zaxxer.hikari.HikariDataSource] [Test worker:13]: HikariPool-3 - Shutdown completed.
2020-07-21 15:57:34.326 INFO  [org.apache.catalina.core.StandardService] [Test worker:13]: Stopping service [Tomcat]
2020-07-21 15:57:34.342 INFO  [org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener] [Test worker:13]: 

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-07-21 15:57:34.345 ERROR [org.springframework.boot.SpringApplication] [Test worker:13]: Application run failed
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.DatabaseException: Table "DATABASECHANGELOG" already exists; SQL statement:

那么我该如何解决这个问题呢? 我的基本理解是,每个测试 class 都会创建自己的 ApplicationContext。 为此,它会创建一个 liquibase bean 并将其加载到其中。 但是,此问题仅发生在 42 次测试中的 2 次。

我真的很想深入了解并了解发生了什么。 任何人都可以阐明我的问题吗?

另外,测试都单独运行良好,但当作为一个组运行时,它们会失败。

UPDATE 1相关属性如下:

spring.main.allow-bean-definition-overriding=true
spring.datasource.url=jdbc:p6spy:h2:mem:testdb;MODE=PostgreSQL;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=FALSE;INIT=CREATE SCHEMA IF NOT EXISTS nmc\\;CREATE SCHEMA IF NOT EXISTS mkt\\;CREATE SCHEMA IF NOT EXISTS cdb\\;CREATE SCHEMA IF NOT EXISTS pg_temp
spring.datasource.driver-class-name=com.p6spy.engine.spy.P6SpyDriver
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.hikari.connectionTimeout=10000
spring.datasource.hikari.idleTimeout=60000
spring.datasource.hikari.maxLifetime=180000
spring.datasource.hikari.maximumPoolSize=50
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console

我的配置是:

@Configuration
@ComponentScan(
    basePackages = {
      "com.aareal.nmc"
    },
    excludeFilters = {
      @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = CommandLineRunner.class)
    })
@EnableTransactionManagement
@Profile("testRegression")
@SpringBootApplication(exclude = SecurityAutoConfiguration.class)
@EnableConfigurationProperties(LiquibaseProperties.class)
public class RegressionTestConfig {

我的两个测试被注释为:

@RunWith(SpringRunner.class)
@SpringBootTest(
    classes = {
      RegressionTestConfig.class
    },
    //webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
    webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)

谢谢

我有同样的问题,它似乎是由对数据库表名进行区分大小写的检查引起的。 也就是说,该表被创建为“DATABASECHANGELOG”,但 Liquibase 正在检查“databasechangelog”是否存在。

修复(至少对于 H2 数据库)是在数据库 URL 中指定不区分大小写的标识符。 例如:

jdbc:h2:mem:~/mydb;CASE_INSENSITIVE_IDENTIFIERS=TRUE

说明: Spring 测试进程启动一个或多个 Spring 容器实例以运行测试。 如果它认为两个测试的配置完全相同,它将重新使用一个实例,否则它将启动一个新实例。 这些实例是共享的,以避免需要为每个测试启动一个全新的 Springboot 应用程序。 但是,问题是实例可能共享一些资源,例如数据库和网络端口。 因此,尝试同时启动多个实例可能会发生错误。 在这种情况下,测试套件正在使用同一个数据库启动两个实例,但第二个实例正在尝试重新运行整个 Liquibase 设置,因为区分大小写的问题意味着它没有看到已经创建的表。

对于我的特殊情况(仅用于内部测试,而不是生产),我有以下内容:

源代码
|-- 主要
|-- 测试
|-- 测试回归

解决方法

  1. 决定要使用的 liquibase 版本(我选择了 4.0.0,这是目前最新的)

  2. 创建一个文件“src/testRegression/java/liquibase/changelog/StandardChangeLogHistoryService.java”

  3. 打开原始的 liquibase 文件“StandardChangeLogHistoryService.java”(我的是在 ~//.gradle/caches/modules-2/files-2.1/org.liquibase/liquibase-core/4.0.0/23a5317eb5005b4765cd85e6f3a2cc4bb55c0daa/liquibase-core-4.0. 0-sources.jar 我复制并解压缩)并将其内容1:1复制到2中新创建的文件中。

  4. 通过更改代码(大约第 396 行)从

     if (SqlGeneratorFactory.getInstance().supports(sql, database)) { executor.execute(sql); getDatabase().commit(); } else {

   if (SqlGeneratorFactory.getInstance().supports(sql, database)) {
    try {
      executor.execute(sql);
      getDatabase().commit();
    } catch (DatabaseException excptn) {
      Scope.getCurrentScope()
          .getLog(getClass())
          .warning(
              "Table '"
                  + getDatabase()
                      .escapeTableName(
                          getLiquibaseCatalogName(),
                          getLiquibaseSchemaName(),
                          getDatabaseChangeLogTableName())
                  + "' already exists.");
    }
  } else {

这只是一种解决方法,因为可能有合理的原因导致 ChangeLogTable 表创建失败。 但是,在我看来,它已经存在不应成为重大失败的原因。

我目前的观点是,这是应该在官方 liquibase 代码库中解决/修复的问题。

以下帖子很有帮助: https://github.com/liquibase/liquibase-cache/issues/1

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM