テストの無いコードはレガシーコードだ!(挨拶

こんにちは、フリューの九岡です。
前回(PlayでRESTful Webサービス))に引き続き、今回はPlayのFunctional Testについて紹介します。

Functional Testって?

「Playのフレームワーク本体と、アプリケーション全体(Model-View-Controller)を通したテスト」です。

Playの公式ドキュメントでは以下のように説明されています。

A functional test is written using JUnit. In this kind of test you can test your application by accessing directly the controller objects.

(訳)
Functional Testを利用すると、Controllerを直接叩く事でアプリケーションをテストできます。

Play framework – Test your application

基本的なパターン

PlayのFunctionalTestでは、フレームワークとアプリケーションを通してテストするために、「HTTPリクエストをシミュレートして、レスポンスを検証」という方法を取ります。
コード例では以下の部分です。

GETHTTP GETリクエスト、OkはHTTPステータスコードの200 OKを意味しています。

HTTPリクエストをシミュレートするメソッドは、GETの他にPOST、DELETE、PUTも用意されています。
レスポンスの検証についても、assertIsOkのようなステータスコードに対するものの他に、レスポンスヘッダやレスポンスボディを検証するメソッドが用意されています。その他、利用可能なメソッドについてはPlayのAPIリファレンスに記載されています。
FunctionalTest (Play! API)

テストクラスの構成

テストクラスは以下の2段構成で、普通のJUnitテストケースと同じです。

  1. テスト環境の準備
  2. 各テストメソッドの実行

テスト環境の準備

Beforeアノテーションをつけたメソッドは各テストメソッドの実行前、BeforeClassはテストクラスの実行前にそれぞれ実行されます。(この二つ以外にもJUnit4が提供しているアノテーションは利用できます。詳しくはJUnit4のドキュメントを参照してください。)
通常、GET以外の操作はデータの追加・削除・更新など何らかの副作用を伴うはずです。そのような場合に、テストメソッドの実行順序でテスト結果が変わってしまうことのないように、BeforeやBeforeClassのタイミングで初期化を行うことをオススメします。
ここでは、テストクラスの実行前にテスト中にずっと使い回す一時ファイルの作成を行っています。また、各テストメソッドの実行前には、

でデータベースの内容を全てクリアした後、

でdata.ymlの内容をDBにロード、さらに各テストケースの事前条件としてPhotoを1件作成してDBに保存しています。

なお、テスト時にはapplication.confでテスト用として指定したDBが利用されます。play newでプロジェクトのひな形を生成したあと、特に変更していなければ、

のようにインメモリーデータベースになっているはずです。

テストメソッドの例

前回実装したPlayでRESTful Webサービスをつくるをネタに、いくつかテストメソッドを書いてみます。

リソースの参照(GET)

テキストの場合

上から順に、HTML・XML・JSONで/photosをリクエストしたときのレスポンスをテストしています。
assertContentTypeでレスポンスのContent-Type、assertCharsetで文字コードが期待通りであることを検証しています。
また、assertIsOkでステータスが”200 OK”であることを検証しています。レスポンスに応じたContent-Type、Charsetをセットするのは忘れがちなので注意したいところです。

バイナリの場合

preparePhoto()で用意しておいたPhotoの画像ファイルを取得するリクエストを送信して、ステータスが200 OK、Content-Typeがimage/pngで、かつ返却されたデータの長さが正しい事を検証しています。
(データの中身を比較しても良かったのですが、ここでは長さで必要十分と判断しました)

リソースの追加(POST)

ファイルを実際にアップロードするリクエストを送信して、レスポンスが正しい事、またアップロードしたファイルの情報がDBに保存されていることを検証しています。
レスポンス(JSON形式)の検証のため、Playに標準添付されているGson(Google製のJSONライブラリ)を利用しています。

リソースの更新(PUT)

Photoのtitleを変更するリクエストを送信して、200 OKが返却されることを確認しています。

リソースの削除(DELETE)

指定したIDのPhotoを削除するリクエストを送信して、200 OKが返却されることを確認しています。

総括

  • PlayでFunctional Testを書きました。
  • Functional Testでは、コントローラに対してGET/POST/PUT/DELETEなどのリクエストを送信して、ステータスコードやレスポンスボディなどが期待通りかを検証することでテストを行います。

Playにはこれ以外にUnit TestとIntegration Testも用意されていますが、投資対効果では個人的にこのFunctional Testが一番だと思います。
また、今回も

ソースコードはGitHubで公開していますので、参考にしてください。
この機会にぜひテストを書いてみましょう!