Spring Boot+Flyway とハマった点

  • 19
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

はじめに

PostgreSQLをJDBCで用いるSpring BootのWebアプリを作ろうとして、Flaywayを入れてみた。

  1. 結果、今まで動いていたテストケースが一斉に失敗するようになった。(H2Databaseが必要)

  2. PostgreSQLを使ってテストケースを実行するためにはContextinitializerの設定が必要だった。

以上2点のメモ。対象のWebアプリはSpring Boot + Apache Wicket (2)で作っていたのとほぼ同等のもの。

Flywayを使うためにやったこと

pom.xmlを変更する。flayway-coreは Spring Bootによってバージョンが自動的に設定される。

pom.xml
<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に設定した。

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を配置するだけ。ちょーかんたん。

v1_0__create-books.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に追加したら解決したよ(意訳)的なことが書いてある。

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:testdbspring.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が利用されるようになった。