Spring Boot+Flyway とハマった点

## はじめに

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

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

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

以上2点のメモ。対象のWebアプリは[Spring Boot + Apache Wicket (2)](http://qiita.com/gishi_yama/items/0c3cc03c2c0030a106fc)で作っていたのとほぼ同等のもの。

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

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

```xml: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に設定した。

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

```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](http://stackoverflow.com/questions/24074749/spring-boot-cannot-determine-embedded-database-driver-class-for-database-type)に行き当たり、h2databaseをpom.xmlに追加したら解決したよ（意訳）的なことが書いてある。

```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:testdb` が `spring.datasource.url` に設定されるようだ。（Spring力低くてあんまり自信ない）

## ハマった点2：PostgreSQLでテストしたいときはどうするの？

折角なのでH2databaseではなく、テスト時もPostgreSQLでFlywayを実行して貰いたいなーとReference Guideを検索してみたら、[ConfigFileApplicationContextInitializer使えばいいのよ](http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html#boot-features-test-utilities)と書いてあった。

テストケースクラスのContextConfigrationでConfigFileApplicationContextInitializer.classを指定してあげると、テストの実行時にapplication.propertiesを読み込んでくれるらしい。

というわけで、テストケースクラスの

```java
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { WebInitializer.class, WicketApplication.class })
public class FooTest {
...
```

のアノテーションの設定を

```java
@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が利用されるようになった。