当前位置: 首页 > 知识库问答 >
问题:

使用liquibase进行Spring引导测试失败

公孙威
2023-03-14

我花了相当长的时间试图找出解决我问题的办法,但毫无结果。

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

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

我的属性(在应用程序testregion.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:

那么我该如何回避这个问题呢?我的基本理解是,每个测试类都创建自己的ApplicationContext。为此,它创建并加载一个液化豆。但是,在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)

谢谢

共有2个答案

潘银龙
2023-03-14

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

src
|--main
|--test
|--test回归

工作区

>

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

    创建一个文件"src/testRegression/java/liquibase/Changelog/Standard/ChangeLog历史ervice.java"

    打开原始的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中新创建的文件中。

    通过更改代码(第396行附近)添加一个catch块

       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

  • 孙元明
    2023-03-14

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

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

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

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

     类似资料:
    • 我打算使用Spring WebFlux为Spring控制器编写一个单元测试。以下是控制器: 这是底层服务接口: 我不明白怎么了。名为的模板位于下。 谢谢大家的支持!

    • 我有一个rest Spring Boot rest API,我想测试它。我可以在Eclipse中手动运行测试(不使用maven,并通过将应用程序作为JUnit测试运行),它运行良好并显示结果,但是不能“工作”,如下所示。 以下是我的POM文件:

    • 我有一个使用Gradle的Spring启动项目设置。我有一个文件,它描述了用于名为'dev'和'prod'的两个环境的设置。 在调用Gradle bootRun任务时,我可以使用中的以下代码将默认环境设置为'dev': 我是否可以假设tomcat会选择'prod'配置,因为如果我不重写它,这似乎是默认行为? 请指教。

    • 我正在尝试测试一个Spring Boot 1.4.0.M3 MVC切片。控制器是这样的。 < code>productshow.html百里香模板的最小化视图如下。 测试类是这样的。 在运行测试时,我得到以下错误。 需要帮助来解决这个问题。提前感谢。

    • 我有一个依赖Spring批处理JobLauncher的类。 我想使用这个JobLauncher的异步版本,所以我创建了一个配置: 我不得不使用,否则当应用程序运行时,其他一些同步JobLauncher会被选中。 现在,在我的测试中,我想使用同步版本来验证作业执行的结果。因此,我在配置中定义了同步bean: 然而,当我的测试运行时。。它总是使用异步版本,我的结果不正确。 是否有一种方法可以在我的测试

    • 问题内容: 我的公司一直在评估Spring MVC,以确定我们是否应该在下一个项目中使用它。到目前为止,我喜欢我所看到的内容,现在,我正在查看Spring Security模块,以确定是否可以/应该使用它。 我们的安全要求非常基本。用户只需要能够提供用户名和密码即可访问网站的某些部分(例如获取有关其帐户的信息);并且网站上的页面很少(常见问题解答,支持等),应该为匿名用户提供访问权限。 在我创建的