SpecsでMockitoを使ってみる

Specsの特徴の1つにMockitoなどのモックライブラリとの連携機能を持っているという点が挙げられます。
もちろんこれらのライブラリはJavaのライブラリなので使おうと思えばそのまま使えるのですが、BDDスタイルでこれらのモックライブラリを使用したテストケースを記述するためのDSLが用意されているということです。
例としてMockitoを使ってみます。テスト対象は以下のような簡単な足し算を実行し、結果をHttpServletRequest#setAttribute()するクラスだとします。

class AddAction {
  def execute(request: HttpServletRequest, 
              response: HttpServletResponse): String = {
    val value1 = request.getParameter("value1").toInt
    val value2 = request.getParameter("value2").toInt
    request.setAttribute("result", value1 + value2)
    return "result.jsp"
  }
}

テストケースは以下のようになります。簡単なモックに対する戻り値の設定などは普通にJavaでMockitoを使うよりも楽になっている気がします。

class AddActionTestSpec extends Specification with Mockito {
  "execute()" should {
    "set result to request attribute" in {
      // テスト対象のアクションクラス
      val action = new AddAction
      // アクションクラスに渡すリクエストとレスポンスのモックを作成
      val request = mock[HttpServletRequest]
      val response = mock[HttpServletResponse]
      // リクエストパラメータの設定
      request.getParameter("value1") returns "1"
      request.getParameter("value2") returns "2"

      // 実行
      val result = action.execute(request, response)

      // 戻り値の確認
      result mustEqual "result.jsp"
      // 計算結果がリクエストにセットされていることを確認
      there was one(request).setAttribute("result", 3)
    }
  }
}

モックの初期化には以下のようにMockitoの@Mockアノテーションを使用することもできます。ミュータブルなフィールドを宣言しないといけないのがちょっといまいちな気もしますが、同じ型のモックを共通的に使用する場合はこんな感じで共通化しておいたほうがよいでしょう。

class AddActionTestSpec extends Specification with Mockito {

  @Mock var request: HttpServletRequest = null
  @Mock var response: HttpServletResponse = null

  def setup(){
    MockitoAnnotations.initMocks(this)
  }

  "execute()" should {
    setup.before
    "set result to request attribute" in {
      // テスト対象のアクション
      val action = new AddAction
      // リクエストパラメータの設定
      request.getParameter("value1") returns "1"
      request.getParameter("value2") returns "2"

      // 実行
      val result = action.execute(request, response)

      // 戻り値の確認
      result mustEqual "result.jsp"
      // 計算結果がリクエストにセットされていることを確認
      there was one(request).setAttribute("result", 3)
    }
  }
}