scalikejdbc-play-fixture-plugin を作りました

(また Play プラグイン作ったのかよと言われそうですが、、、)



おしごと的な Play アプリでは Fixture 機能を自前実装して、それでテストをしていました。
ただ、scalikejdbc に依存していたため、そこだけ切り出して Play プラグインにするとかはしてませんでした。でもよく考えたら scalikejdbc-play-plugin 自体に Fixture 機能つけちゃえばいいんじゃね?ってことで実装し、scalikejdbc 1.5.2 から入りました。
http://notes.implicit.ly/post/47241249711/scalikejdbc-1-5-2

scalikejdbc-play-plugin に組み込もうと思ったんですが、実装してから Play 2.0 にはない play.api.Configuration#getStringList を使っていることがわかりました。なのでこの機能は scalikejdbc-play-fixture-plugin として scalikejdbc-play-plugin とは別のものになり、 Play 2.1 からのサポートです。


それ evolutions でできるよ、と思う方がいるかもしれませんが、evolutions はデータベースマイグレーションの仕組みであり、データの投入ツールではないです。あと、この前のエントリに書いたようなプラグイン同士の依存関係の問題があり、scalikejdbc と evolutions の併用はあまりしたくないです。

インストール

build.sbt はこんな感じ

val appDependencies = Seq(
  "com.github.seratch" %% "scalikejdbc"                     % "[1.5,)",
  "com.github.seratch" %% "scalikejdbc-play-plugin"         % "[1.5,)",
  "com.github.seratch" %% "scalikejdbc-play-fixture-plugin" % "[1.5,)"
)

conf/play.plugins はこう。PlayFixturePlugin を使うには PlayPlugin がすでにロードされている必要があることに注意してください。

10000:scalikejdbc.PlayPlugin
11000:scalikejdbc.PlayFixturePlugin

使い方

Fixture はよく yaml とかのフォーマットで用意したりしますが、Play は evolutions がああですから、Plain SQL をそのまま使えばいいだろうってことにしました。
ファイルの中身も evolutions をパクって、Ups と Downs に分けました。Ups はアプリの起動時に読み込まれ、Downs は終了時に実行されます。

#!Ups
INSERT INTO message (name, message) VALUES ('toshi', 'hello');
...

#!Downs
DELETE FROM message;


このファイルを conf/db/fixtures/${dbname}/message.sql として保存します。
default データベースなら conf/db/fixtures/default/message.sql になります。

conf/db/fixtures 以下に置いたファイルのうちどれを使うかは、application.conf で設定します。
設定キーは開発モードとテストモードで別の fixture を使えるように分けました。


開発用は

     db.default.fixtures.dev="insert_data.sql"


テスト用は

     db.default.fixtures.test="insert_data.sql"


fixture スクリプトは複数指定することもできます。

     db.default.fixtures.dev=[ "insert_data.sql", "insert_additional_data.sql" ]


複数指定した場合は、指定した順番で SQL が実行されます。(Downs は逆に実行されます。)

テスト

テストのときは FakeApplication を使えば application.conf の設定を上書きして Fixture を切り替えることも可能です。

  running (FakeApplication(
    additionalConfiguration =
      Map("db.default.fixtures.test" -> 
        List("insert_test_data.sql", "insert_test_data2.sql").asJava) ++
      inMemoryDatabase(name = "default",
                       options = Map("DB_CLOSE_DELAY" -> "-1")))) {
                         
      // test ....

  }


asJava しなきゃいけないのがいけてないですね。Play が typesafe-config をラップしきれてないせいです。
これは pull request を送って取り込まれたのでそのうち書かなくてもよくなります。
https://github.com/playframework/Play20/pull/938

サンプルアプリ

https://github.com/seratch/scalikejdbc/tree/1.5.2/scalikejdbc-play-plugin/test/zentasks
Play 付属のサンプル、zentasks を scalikejdbc に変えたものです。
(ちなみに マイグレーションには evolutions ではなく play-flyway を使っています。)



scalikejdbc は最近いろいろ機能が増えてきて、なんかすごいことになってるのですが、
あまり伝わってなさげなので、そろそろドキュメントとかに力入れたほうがいいのかもですね。