Play frameworkでテストコードを作成してみた。

##Play frameworkでのテストコード
Play frameworkでjunitを使ってテストコードを作成したのでメモ。

Playでプロジェクトを作成するとtest/controllersディレクトリ内にデフォルトでHomeControllerTest.javaが入っている。

```java:HomeControllerTest.java
package controllers;

import org.junit.Test;
import play.Application;
import play.inject.guice.GuiceApplicationBuilder;
import play.mvc.Http;
import play.mvc.Result;
import play.test.WithApplication;

import static org.junit.Assert.assertEquals;
import static play.mvc.Http.Status.OK;
import static play.test.Helpers.GET;
import static play.test.Helpers.route;

public class HomeControllerTest extends WithApplication {

    @Override
    protected Application provideApplication() {
        return new GuiceApplicationBuilder().build();
    }

    @Test
    public void testIndex() {
        Http.RequestBuilder request = new Http.RequestBuilder()
                .method(GET)
                .uri("/");

        Result result = route(app, request);
        assertEquals(OK, result.status());
    }

}

```

テストメソッドの前には@Testのアノテーションが入り、テストメソッドは返り値なし。
ちなみにメソッド名は日本語でも良い(むしろ日本語の方がテスト内容がわかりやすかったりする)。
デフォルトで入っているテストのtestIndex()はインデックスページが表示されるかを確認している。
表示されたかどうかはassertEqualsメソッドでチェックしていて、`assertEquals(予想される値, 実際の値)`で使う。
トップページが表示されるとステータスコードでOKが返されるのでそれで確認をしている。

他にもリダイレクトのチェックをしたいなら
`assertEquals(SEE_OTHER, result.status())`
リダイレクト先のチェックをしたいなら(リダイレクト先が/hogeの場合)
`assertEquals("/hoge", result.redirectLocation().get())`
などいろいろチェックできる。

###投稿ができるかどうかのテストをしたい場合

```java
    @Test
    public void 掲示板に投稿できるか() {
        Http.RequestBuilder request = Helpers.fakeRequest()
                .method(POST)
                .bodyForm(ImmutableMap.of("title", "タイトルです", "message", "メッセージです。"))
                .uri("/create");

        int post_num = Post.find.all.size(); // 投稿前のデータベース上の投稿数を取得している
        
        Result result = route(app, request);

        assertEquals(post_num + 1,  Post.find.all.size());
    }

```
これは掲示板に投稿できるかどうかを確認するためのテスト。
投稿のチェックは投稿前と後でデータベース内の投稿数が1つ多くなる。
なので
`投稿前の投稿数 + 1 = 投稿後の投稿数`
がなり立てば投稿ができていることになる。


###バリデーションがちゃんと動くかのテストがしたい場合

```java
    @Test
    public void emailもpasswordも未入力の場合はバリデーションエラー() {
        Http.RequestBuilder request = Helpers.fakeRequest()
                .method(POST)
                .bodyForm(ImmutableMap.of("email", "", "password", ""))
                .uri("/logincheck");

        request = CSRFTokenHelper.addCSRFToken(request);

        Result result = route(app, request);
        assertEquals(BAD_REQUEST, result.status());
    }
```
これはログインフォームにemailとパスワードが空の状態で送信したらバリデーションに引っかかりBad Requestを返す処理をテストしている。
`CSRFTokenHelper.addCSRFToken(request);`でCSRFトークンをリクエストに追加しているが、これが無いと
`failed: java.lang.RuntimeException: No CSRF token was generated for this request! Is the CSRF filter installed?`
というエラーが出て怒られる。
基本的にPlay frameworkでは自動でCSRFトークンが生成されるが、バリデーションに引っかかるような場合はされないのかもしれない。


###ログインしているかどうかで処理が変わるものをテストする場合
例えばログイン中にログイン画面(IDやパスワードを入力するためのページ)にアクセスできたらおかしいので、もしユーザーがログイン画面のURIにアクセスしたらリダイレクトさせる必要がある。

```java
    @Test
    public void ログイン中はloginページを表示できない() {
        Http.RequestBuilder request = Helpers.fakeRequest()
                .method(GET)
                .uri("/login");

        request.session("login", User.finder.byId(1).getEmail()); // IDが1のユーザーをログインさせる
        
        Result result = route(app, request);
        assertEquals(SEE_OTHER, result.status()); // リダイレクトするかチェック
        assertEquals("/", result.redirectLocation().get());
    }

```
sessionメソッドを使用してログイン状態を作り出した。
使い方は`session("session名", セッションに保存させたい値)`
テストメソッド内で保存したsessionはそのテストメソッド終了と同時に破棄される。