Тесты не работают для нескольких источников данных с жидкой базой с пружинной загрузкой - PullRequest
0 голосов
/ 09 апреля 2020

Я создаю юнит-тестирование для приложения с весенней загрузкой, имеющего несколько источников данных. (Конфигурация сильно зависит от этого ответа)

@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 в качестве тестовой зависимости и добавил h2 в URL источника данных, а также в application.yaml для тестирования.

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

Я создал хранилище , чтобы продемонстрировать это.

Когда я делаю 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

Не уверен, какое изменение конфигурации мне не хватает.

1 Ответ

0 голосов
/ 23 апреля 2020

Для его работы необходимо выполнить несколько настроек:

  1. Исключить автоконфигурацию для БД и Liquibase в вашем CarApplication. java

    @ SpringBootApplication (исключить = {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());
    }
}

Result :-)

...