【问题标题】:Tests not working for multiple datasource with spring boot liquibase使用 Spring Boot liquibase 测试不适用于多个数据源
【发布时间】:2020-07-22 04:26:59
【问题描述】:

我正在为具有多个数据源的 Spring Boot 应用程序创建单元测试。 (配置深受this 回答的启发)

@Configuration
public class DatasourceConfig {

    @Primary
    @Bean
    @ConfigurationProperties(prefix = "datasource.primary")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties(prefix = "datasource.primary.liquibase")
    public LiquibaseProperties primaryLiquibaseProperties() {
        return new LiquibaseProperties();
    }

    @Bean
    public SpringLiquibase primaryLiquibase() {
        return springLiquibase(primaryDataSource(), primaryLiquibaseProperties());
    }

    @Bean
    @ConfigurationProperties(prefix = "datasource.secondary")
    public DataSource secondaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties(prefix = "datasource.secondary.liquibase")
    public LiquibaseProperties secondaryLiquibaseProperties() {
        return new LiquibaseProperties();
    }

    @Bean
    public SpringLiquibase secondaryLiquibase() {
        return springLiquibase(secondaryDataSource(), secondaryLiquibaseProperties());
    }

    private static SpringLiquibase springLiquibase(DataSource dataSource, LiquibaseProperties properties) {
        SpringLiquibase liquibase = new SpringLiquibase();
        liquibase.setDataSource(dataSource);
        liquibase.setChangeLog(properties.getChangeLog());
        liquibase.setContexts(properties.getContexts());
        liquibase.setDefaultSchema(properties.getDefaultSchema());
        liquibase.setDropFirst(properties.isDropFirst());
        liquibase.setShouldRun(properties.isEnabled());
        liquibase.setLabels(properties.getLabels());
        liquibase.setChangeLogParameters(properties.getParameters());
        liquibase.setRollbackFile(properties.getRollbackFile());
        return liquibase;
    }


...

}

datasource:
  primary:
    url: jdbc:mysql://localhost/primary
    username: username
    password: password
    liquibase:
      change-log: classpath:/db/changelog/db.primary.changelog-master.xml
  secondary:
    url: jdbc:mysql://localhost/secondary
    username: username
    password: password
    liquibase:
      change-log: classpath:/db/changelog/db.secondary.changelog-master.xml

应用程序运行正常。

问题是使用此配置的单元测试失败。我使用h2 作为嵌入式数据库。添加 h2 作为测试依赖,并在数据源 URL 以及 application.yaml 中添加 h2 进行测试。

用于测试的application.yaml

management:
  endpoints.web.exposure.include: "*"
  security.enabled: false
spring:
  zipkin:
    discoveryClientEnabled: false
    sender:
      type: kafka
      #type: web
  liquibase:
    enabled: false
  datasource:
    url: "jdbc:h2:mem:testdb"
    jdbc-url: "jdbc:h2:mem:testdb"
    username: sa
    password:
  secondary-datasource:
    url: "jdbc:h2:mem:testdb"
    jdbc-url: "jdbc:h2:mem:testdb"
    username: sa
    password:
datasource:
 primary-liquibase:
   liquibase:
     url: "jdbc:h2:mem:testdb"
     username: sa
     password:
 secondary-liquibase:
   liquibase:
     url: "jdbc:h2:mem:testdb"
     username: sa
     password:
liquibase:
  enable: false

单元测试文件

package com.foo.bar.car;

import com.foo.bar.car.utils.KSUIDGenerator;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.boot.jdbc.EmbeddedDatabaseConnection;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
@AutoConfigureMockMvc
@AutoConfigureTestDatabase
// https://stackoverflow.com/a/58786742/1534925
//@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
//@AutoConfigureTestDatabase(connection = EmbeddedDatabaseConnection.H2)
class CarApplicationTests {

    @Test
    public void contextLoads() {
        String h = "Hello World!";
        Assertions.assertEquals(h, "Hello World!");
    }

    @Test
    public void testKSUIDGeneration() {
        Assertions.assertNotNull(KSUIDGenerator.generateKSUID());
    }
}

我创建了一个repository 来演示这一点。

当我执行gradlew clean check 时,会出现以下错误

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [liquibase.integration.spring.SpringLiquibase]: Factory method 'primaryLiquibase' threw exception; nested exception is java.lang.IllegalArgumentException: No visible constructors in class org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration$EmbeddedDataSourceFactoryBean

不确定我缺少什么配置更改。

【问题讨论】:

    标签: spring-boot unit-testing liquibase spring-boot-test


    【解决方案1】:

    要使其发挥作用,需要进行几项调整:

    1. 在 CarApplication.java 中排除 DB 和 Liquibase 的自动配置

      @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, LiquibaseAutoConfiguration.class })

    2. 去掉配置中的sping前缀(在应用和测试属性中)

    3. 将 liquibase 更改日志位置添加到测试属性

    仔细检查下面的设置,以防在上面列出的所有调整之后它无法工作(我在这里和那里改变了我通常编码的方式以使我感到舒适):

    CarApplication.java

    @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, 
                                       LiquibaseAutoConfiguration.class })
    public class CarApplication {
      public static void main(String[] args) {
        SpringApplication.run(CarApplication.class, args);
      }
    }
    

    application.yaml

    server:
      port: 9999
    
    datasource:
      url: jdbc:postgresql://localhost:8888/foo
      jdbcUrl: jdbc:postgresql://localhost:5432/foo
      username: username
      password: password
      driverClassName: org.postgresql.Driver
      liquibase:
        change-log: classpath:db-changelog/primary.xml
    
    secondary-datasource:
      url: jdbc:postgresql://localhost:8888/bar
      jdbcUrl: jdbc:postgresql://localhost:5432/bar
      username: username
      password: password
      driverClassName: org.postgresql.Driver
      liquibase:
        change-log: classpath:db-changelog/secondary.xml
    

    DatabaseConfig.java

    @Configuration
    public class DatabaseConfig {
    
        @Bean
        @Primary
        @ConfigurationProperties(prefix = "datasource")
        public DataSource primaryDataSource() {
            return DataSourceBuilder.create().build();
        }
    
        @Bean
        @ConfigurationProperties(prefix = "secondary-datasource")
        public DataSource secondaryDataSource() {
            return DataSourceBuilder.create().build();
        }
    
        @Bean
        @ConfigurationProperties(prefix = "datasource.liquibase")
        public LiquibaseProperties primaryLiquibaseProperties() {
            return new LiquibaseProperties();
        }
    
        @Bean("liquibase")
        public SpringLiquibase primaryLiquibase() {
            return springLiquibase(primaryDataSource(), primaryLiquibaseProperties());
        }
    
        @Bean
        @ConfigurationProperties(prefix = "secondary-datasource.liquibase")
        public LiquibaseProperties secondaryLiquibaseProperties() {
            return new LiquibaseProperties();
        }
    
        @Bean
        public SpringLiquibase secondaryLiquibase() {
            return springLiquibase(secondaryDataSource(), secondaryLiquibaseProperties());
        }
    
        private static SpringLiquibase springLiquibase(DataSource dataSource, LiquibaseProperties properties) {
            SpringLiquibase liquibase = new SpringLiquibase();
            liquibase.setDataSource(dataSource);
            liquibase.setChangeLog(properties.getChangeLog());
            liquibase.setContexts(properties.getContexts());
            liquibase.setDefaultSchema(properties.getDefaultSchema());
            liquibase.setDropFirst(properties.isDropFirst());
            liquibase.setShouldRun(properties.isEnabled());
            liquibase.setLabels(properties.getLabels());
            liquibase.setChangeLogParameters(properties.getParameters());
            liquibase.setRollbackFile(properties.getRollbackFile());
            return liquibase;
        }
    }
    

    测试application.yaml

    datasource:
      url: "jdbc:h2:mem:testdb"
      jdbc-url: "jdbc:h2:mem:testdb"
      username: sa
      password:
      liquibase:
        change-log: classpath:db-changelog/primary.xml
    
    secondary-datasource:
      url: "jdbc:h2:mem:testdb"
      jdbc-url: "jdbc:h2:mem:testdb"
      username: sa
      password:
      liquibase:
        change-log: classpath:db-changelog/secondary.xml
    

    CarApplicationTest.java

    @SpringBootTest
    class CarApplicationTests {
        @Test
        public void contextLoads() {
            String h = "Hello World!";
            Assertions.assertEquals(h, "Hello World!");
        }
        @Test
        public void testKSUIDGeneration() {
            Assertions.assertNotNull(KSUIDGenerator.generateKSUID());
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2017-05-15
      • 2021-11-02
      • 2022-01-22
      • 2019-11-24
      • 2015-08-27
      • 1970-01-01
      • 1970-01-01
      • 2016-04-17
      • 2020-11-12
      相关资源
      最近更新 更多