Posted at

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 {
}