cobonas

2014.12.08

Play Framework(Play2)(Scala)のTips Part2:Specs2とMockitoでテストを書く(Advent Calendar 8日目)

この記事はアライドアーキテクツAdvent Calendar 8日目の記事です。

どうも。謎の刺客Tarou Yamadaさんにカレンダーを乗っ取られてしまった伊藤(係長)です。
気を取り直して、今回はSpecs2とMockitoを使ったユニットテストのお話を書きます。

■Specs2とは
Scala用のテスティングフレームワークです。BDD(振る舞い駆動開発)スタイルでテストケースを
記述する事ができます。
詳しくはこちらをご覧ください。

■Mockitoとは
簡単に言うとテスト時に邪魔になる(依存している)クラスをモック(ハリボテ)にして、
単体テストを書きやすくするモックフレームワークです。
詳しくはこちらをご覧ください。

■前提
こんな実装があったとして、HogeServiceのテストを書こうとします。

Fuga.scala

HogeService.scala

見ての通り、HogeService#doSomething()はFugaオブジェクトに依存しています。
そのままテストを書いて実行しようとすると、毎回DB接続が必要になってしまいます。
これではあまりよろしくないので、Fugaクラスをモックにします。

■モック化の準備
では早速Fugaをモックにしましょう、と行きたいところですが、
HogeServiceとFugaはobjectとして定義されています。
objectとは、Scalaで簡単にシングルトンを定義できるキーワードですね。
手軽にシングルトンを定義できるので、結構多用している方も多いのではないでしょうか。
このままではHogeServiceで使用しているFugaをモック化して差し込む事ができません。
(objectはモック化する事ができません。)
そこで、実装を次の通りに変更します。

Fuga.scala

HogeService.scala

実装の本体をclassで定義して、それを継承したobjectを定義しました。
HogeServiceでは、依存しているFugaをvalでフィールド定義します。
こうする事でFugaをモック化してHogeServiceに差し込む事が可能となります。
(※他にもやり方は何通りかあると思いますがその一例です。)

■テストコード
ここまででモックしてテストコードを書く準備が整いましたので、
実際にテストを書いてみます。

HogeServiceSpec.scala

これでOKです。
Fuga#findById()とFuga#update()はモック化されていますので、DB接続は行われません。
ここではFuga#update()が正しい引数で呼ばれている事を確認しています。

■spy
Mockitoにはspyというスバラシイ機能があります。
これは、テスト対象のクラスの一部分だけモック化できるというものです。
(パーシャルモックと言います)
実際のコードを見てみましょう。

Hoge.scala

isHogeの結果は、isFugaかisPiyoの結果で決まります。
そのままisHogeをテストしようとすると、設定ファイルとDBを見に行ってしまうので
あまりよろしくありません。

■テストコード
spyを使う事で次のように書く事ができます。
HogeSpec.scala

これで同一クラス内に定義されている関数をダマして、設定ファイルやDBを見に行かなくてもテストできるようになりました。

今回紹介したのはSpecs2、Mockitoの機能の内、ほん〜の一部だけですので、
実際触って見て色々試してみると良いと思います。

明日は、最近乗りに乗っているGit大佐こと大佐の番です!!!