JUnit
DBUnit
spring-boot
Flyway

JUnit にて Flyway を起動した際、schema_version テーブルが存在しないと表示される現象について

More than 1 year has passed since last update.

概要

こちらの記事 を拝見させていただき、これは便利と、JUnit から DBUnit を使用してテストすることを考えました。しかしながら、下記構成にて JUnit からテストを実施した際、Flyway にて作成されているはずの、schema_version テーブルを DBUnit が確認できない現象が発生しました。

Spring Boot
JUnit
|---> Flyway (マイグレーションの DDL を実行)
|---> DBUnit (単体テスト用の CSV を投入)

現象の詳細

DBUnit で使用する TransactionAwareDatasourceProxy をコンテナに登録しています。

TestConfig.java
@TestConfiguration
@ComponentScan(basePackages = {"com.hoge.huga"})
public class TestConfig {

    @Autowired
    Environment environment;

    @Bean
    public TransactionAwareDataSourceProxy dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE");

        dataSource.setUsername("sa");
        dataSource.setPassword("");
        return new TransactionAwareDataSourceProxy(dataSource);
    }

ApplicationContext#getBean(TestConfig.class) にて上記をコンテナから取得しようとしておりましたが、下記を実施し、該当のクラスをコンテナに登録すると、getBean にて Bean を取得する前に実行される、DBUnit による flyway の schema_version テーブルのアクセスが失敗しました。

HogeTest.java
public class Hoge {
    @Before
    public void setUp() {
       ApplicationContext context = new AnnotationConfigApplicationContext(TestConfig.class);
    }
}
ログの内容
Caused by: org.h2.jdbc.JdbcSQLException: テーブル "schema_version" が見つかりません
Table "schema_version" not found; SQL statement:
SELECT "version_rank","installed_rank","version","description","type","script","checksum","installed_on","installed_by","execution_time","success" FROM "public"."schema_version" ORDER BY "version_rank" [42102-195]

原因

DBUnit のコネクション確立時に、単体テスト用の application.properties を読み込めていないためであると考えられます。
ApplicationContext のインスタンス化直前でブレークすると、IDE 上のログには下記が出力されており、schema_version のテーブルを作成されていることを確認できました。

DEBUG-2017-09-11 20:12:07,895---org.flywaydb.core.internal.dbsupport.SqlScript-40-main-Found statement at line 17: CREATE TABLE "PUBLIC"."schema_version" (
    "version_rank" INT NOT NULL,
    "installed_rank" INT NOT NULL,
    "version" VARCHAR(50) NOT NULL,
    "description" VARCHAR(200) NOT NULL,
    "type" VARCHAR(20) NOT NULL,
    "script" VARCHAR(1000) NOT NULL,
    "checksum" INT,
    "installed_by" VARCHAR(100) NOT NULL,
    "installed_on" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    "execution_time" INT NOT NULL,
    "success" BOOLEAN NOT NULL
)

しかしながら、デバッグ実行して確認したところ、上記のエラーが発生した場合、@Autowired した Environment オブジェクトの ActiveProfile が NULL となっていました。
これは、下記の構成にて Profile で読み込む application.properties を切り替えているためであると考えられます。

・main
    |- java
         |- com.config
                 |- DevEnvironement.java (@PropertySource("classpath:application-dev.properties”) @Profile("dev”))
                 |- LocalEnvironement.java (@PropertySource("classpath:application-local.properties”) @Profile(“local”))
    |- resources
         |- application-dev.properties
         |- application-local.properties
・test
    |- resources
          |-  application.properties

補足
^^^^
コンテナに登録しないクラスでは、@Autowired ができないため、Environment オブジェクトを参照できません。
コンテナに登録していないオブジェクトにおいても、Environment#getProperty をするため下記のようなプロキシの形式にて Environment オブジェクトを取得しています。

HogeEnvironment.java
public HogeEnvironment {
private static Environment hogeEnvironment;

static {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(HogeApplication.class);
    hogeEnvironment = context.getEnvironment();

}

回避策

テストクラスにおいて、テストクラス用の application.properties を読み込むよう変更することで回避できることが確認できました。
この際、こちらの記事 にて紹介されている現象が発生するので、test/resources/application.properties の名称を変更して、application-unit.properties にしました。

UnitEnvironment.java
@Configuration
@Profile("unit")
@PropertySource("classpath:application-unit.properties")
public class UnitEnvironment  {
}