簡體   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