本文介绍了使用Spring Boot Liquibase测试不适用于多个数据源的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am creating unittesting for spring boot application having multiple datasources. (Configuration is heavily inspired from this answer)

@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进行测试.

The problem is unit testing is failing with this configuration. I have used h2 as embedded DB. Added h2 as test dependency and added h2 in datasource URL as well in application.yaml for testing.

application.yaml用于测试

application.yaml for testing

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());
    }
}

我创建了一个存储库进行演示.

I have created a repository to demonstrate this.

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

When I do gradlew clean check it gives me following error

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

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

Not sure what configuration change I am missing.

推荐答案

要使其正常运行,需要进行一些调整:

There are several adjustments to be done to make it work:

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

  1. Exclude Autoconfiguration for DB and Liquibase in your CarApplication.java

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

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

摆脱配置中的sping前缀(包括应用程序和测试属性)

Get rid of sping prefix in your configuration (both in app and test properties)

添加liquibase更改日志位置以测试属性

Add liquibase changelog location to test properties

仔细检查下面的设置,以防在上面列出的所有调整之后仍然无法正常工作(我在这里和那里更改了内容,通常使用使我感到舒服的方式进行编码):

Double check with the setup below in case it wont work after all listed above adjustments (I changed things here and there the way I usually code to make it comfortable to me):

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());
    }
}

这篇关于使用Spring Boot Liquibase测试不适用于多个数据源的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-12 18:00