概要
SpringBoot環境でDBUnitを使う際、spring-test-dbunitを使うとアノテーションで指定するだけでデータベースのセットアップとアサーションができて便利ですね。
spring-test-dbunitは2021年8月現在最終コミットが2016年となっていて、残念ながら更新は完全に止まってしまっているのですが、まだそこそこ使われているようです。
ここではDBUnit + spring-test-dbunitを複数スキーマ切ってあるMySQLで使う際の問題について扱いますので、導入などは他の記事を参考にしてください。
問題
ひとつのDBにテスト用のスキーマと検証用のスキーマがある等、複数スキーマの環境でDBUnit + spring-test-dbunitを使うとAmbiguousTableNameExceptionが起きて困りました。
(特に制約がなければテストで使用するDBをH2などのインメモリDBにすればこのような問題は起きないしそうしたいところですが…)
スキーマは指定しているのですがどうやら正しく処理がされていないようです。
どう設定すればよかったか
DBUnitが使用するコネクションをDataSourceベースのDatabaseDataSourceConnectionにし、MetadataHandlerとしてMySqlMetadataHandlerを設定します。
@Configuration
public class TestConfig {
@Autowired
private DataSource dataSource;
@Bean
public IDatabaseConnection dbUnitDatabaseConnection() throws SQLException {
// DatabaseDataSourceConnectionを使用する。テーブル名曖昧問題を解決するにはここでスキーマ名を設定する必要がある
// afterTestMethodでconnectionのcloseがされるのでDataSourceベースでないクラスを設定すると
// 2つ目以降のテストでconnectionがclose済みとなり失敗する
IDatabaseConnection conn = new DatabaseDataSourceConnection(dataSource, "schema_for_test");
// MetadataHandlerをMySqlMetadataHandlerに設定する
// この設定をしないとSchema修飾が正しく処理されずスキーマ間で同じ名前のテーブルがあるDBを扱うと失敗する
conn.getConfig().setProperty(DatabaseConfig.PROPERTY_METADATA_HANDLER, new MySqlMetadataHandler());
conn.getConfig().setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, new MySqlDataTypeFactory());
return conn;
}
}
解説
spring-test-dbunitは、DBUnitが使用するコネクションとして、DataSourceかIDatabaseConnectionのいずれかを探して使用しようとします。
テーブル名曖昧問題が起きなければDataSourceで恐らく問題ないと思いますが、DataSourceだとスキーマを指定していても動作してくれないためIDatabaseConnectionを使う必要があると思います。
IDatabaseConnectionの実装として、MySqlConnectionを指定すればテーブル名曖昧問題は解決するのですが、その場合別の問題が起きます。
spring-test-dbunitを使用するとafterTestMethodでconnectionのcloseが呼ばれるため、MySqlConnectionだとDBUnitのテストが2つ以上あるときに最初のテスト以外は Connection is closed
といったメッセージとともに失敗してしまいます。
よってDataSourceベースのDatabaseDataSourceConnectionを使用します。これでコネクションクローズ問題は解消するのですが、そのままだと相変わらずテーブル名曖昧問題は起こるままです。MetadataHandler#getSchema(ResultSet)の実装がDefaultMetadataHandlerだとMySQLのときにスキーマ名が取得できないのが原因で、上で示したようにMetadataHandlerとしてMySqlMetadataHandlerを設定することでテーブル名曖昧問題も解決となります。
なおDBUnitは2.7.2、spring-test-dbunitは1.3.0、コネクションプール実装としてはHikariCPで上記設定の動作を確認しています。
リンク
Spring Test DBUnit – Introduction
DbUnit – Configurable Features and Properties