はじめに
PostgreSQLをJDBCで用いるSpring BootのWebアプリを作ろうとして、Flaywayを入れてみた。
-
結果、今まで動いていたテストケースが一斉に失敗するようになった。(H2Databaseが必要)
-
PostgreSQLを使ってテストケースを実行するためにはContextinitializerの設定が必要だった。
以上2点のメモ。対象のWebアプリはSpring Boot + Apache Wicket (2)で作っていたのとほぼ同等のもの。
Flywayを使うためにやったこと
pom.xmlを変更する。flayway-coreは Spring Bootによってバージョンが自動的に設定される。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.3-1102-jdbc41</version>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
次にRDBの設定をSpring Boot に喰わせる。この場合はapplication.propertiesに設定した。
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/foo
spring.datasource.username=bar
spring.datasource.password=baz
あとはsrc/main/resourcesに、db.migration
パッケージを掘って、Flyway用のsqlを配置するだけ。ちょーかんたん。
-- For example...
create table books (
isbn text primary key,
book_name text not null,
);
これでSpring Bootを起動すると、RDB(PostgreSQL)のfooデータベースにbooksテーブルを生成してくれるし、SQLファイルをFlywayのルールに沿って増やしてあげるとマイグレーションしてくれる仕組みが整う。
ハマった点1:テストケースが動かない
「いやあ簡単に導入できた、良かった良かった」と気分良くテストケースを実行すると、テストケースが全て失敗し、真っ赤な世界に突入してしまった。
エラーログを追ってみると、いろいろ書いてあるんだけど、
Caused by: org. springframework. beans. factory. BeanCreationException: Cannot determine embedded database driver class for database type NONE. If you want an embedded database please put a supported one on the classpath.
とか言われてるのが怪しいと思われる。
これをキーに検索してみると、Spring Boot - Cannot determine embedded database driver class for database type NONEに行き当たり、h2databaseをpom.xmlに追加したら解決したよ(意訳)的なことが書いてある。
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
H2databaseをpom.xmlに追加してみると、
INFO --- [ main] o.f.c.i.dbsupport.DbSupportFactory : Database: jdbc:h2:mem:testdb (H2 1.4)
INFO --- [ main] o.f.core.internal.command.DbValidate : Validated 1 migration (execution time 00:00.019s)
INFO --- [ main] o.f.c.i.metadatatable.MetaDataTableImpl : Creating Metadata table: "PUBLIC"."schema_version"
INFO --- [ main] o.f.core.internal.command.DbMigrate : Current version of schema "PUBLIC": << Empty Schema >>
INFO --- [ main] o.f.core.internal.command.DbMigrate : Migrating schema "PUBLIC" to version 1.0
INFO --- [ main] o.f.core.internal.command.DbMigrate : Successfully applied 1 migration to schema "PUBLIC" (execution time 00:00.045s)
といった感じで、テストケースは(実行時にflywayが実行されて)正常終了するようになった。
Spring Bootでflywayを使うようなプロジェクトのテスト時には、標準で jdbc:h2:mem:testdb
が spring.datasource.url
に設定されるようだ。(Spring力低くてあんまり自信ない)
ハマった点2:PostgreSQLでテストしたいときはどうするの?
折角なのでH2databaseではなく、テスト時もPostgreSQLでFlywayを実行して貰いたいなーとReference Guideを検索してみたら、ConfigFileApplicationContextInitializer使えばいいのよと書いてあった。
テストケースクラスのContextConfigrationでConfigFileApplicationContextInitializer.classを指定してあげると、テストの実行時にapplication.propertiesを読み込んでくれるらしい。
というわけで、テストケースクラスの
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { WebInitializer.class, WicketApplication.class })
public class FooTest {
...
のアノテーションの設定を
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
classes = { WebInitializer.class, WicketApplication.class },
initializers = ConfigFileApplicationContextInitializer.class)
public class FooTest {
...
と変更した。またpom.xmlのh2databaseのdependencyは取り除いた。実行してみると、
INFO --- [ main] o.f.c.i.dbsupport.DbSupportFactory : Database: jdbc:postgresql://localhost:5432/foo (PostgreSQL 9.4)
INFO --- [ main] o.f.core.internal.command.DbValidate : Validated 1 migration (execution time 00:00.023s)
INFO --- [ main] o.f.c.i.metadatatable.MetaDataTableImpl : Creating Metadata table: "public"."schema_version"
INFO --- [ main] o.f.core.internal.command.DbMigrate : Current version of schema "public": << Empty Schema >>
INFO --- [ main] o.f.core.internal.command.DbMigrate : Migrating schema "public" to version 1.0
INFO --- [ main] o.f.core.internal.command.DbMigrate : Successfully applied 1 migration to schema "public" (execution time 00:00.064s).
無事、テスト時にもapplication.propertiesの値を読み込んで、PostgreSQLが利用されるようになった。