概要
こちらの記事 を拝見させていただき、これは便利と、JUnit から DBUnit を使用してテストすることを考えました。しかしながら、下記構成にて JUnit からテストを実施した際、Flyway にて作成されているはずの、schema_version テーブルを DBUnit が確認できない現象が発生しました。
Spring Boot
JUnit
|---> Flyway (マイグレーションの DDL を実行)
|---> DBUnit (単体テスト用の CSV を投入)
現象の詳細
DBUnit で使用する TransactionAwareDatasourceProxy をコンテナに登録しています。
@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 テーブルのアクセスが失敗しました。
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 オブジェクトを取得しています。
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 にしました。
@Configuration
@Profile("unit")
@PropertySource("classpath:application-unit.properties")
public class UnitEnvironment {
}