2011年8月21日日曜日

Slim3でValidationのテスト

Slim3でValidationのテスト


元ネタは次のページです。

う~ん、いい感じですね

フォームを作成していい感じの値が入ってきた場合のテストの書き方と、Validationを使った場合のエラーメッセージの取得の実装方法。非常に参考になります。
では、Validationのテストを行っていい感じでない値が入ってきた場合のテストをどう書こうかな?

というわけで、Validationでエラーとした場合のテストを書いてみることにしました。

簡単に設計

こんな感じの設計とテスト設計です。

そうだTODOを作成しよう

というわけで、上のストーリーにしたがって、ToDoリストを作成しましょう。
  • メールアドレスを送ったあとに同じ画面に戻ってくる。
  • Validation Errorとなった場合に、エラーメッセージが作成される。
  • Emailは必須。
  • EmailはEmailとして妥当な文字列。

早速テストとControllerを作成

さっきのフォームの作成を参考に、Controllerとかテストとかを作ります。

名前はMailControllerMailControllerTestにしておきます。

なお、元の画面に戻したいので、MailControllerTestでは、すでにリダイレクト先を変更しておきます。

MailController

package orz.mikeneck.mail;

import org.slim3.controller.Controller;
import org.slim3.controller.Navigation;

public class MailController extends Controller {

    @Override
    public Navigation run() throws Exception {
        return null;
    }
}


MailControllerTest

package orz.mikeneck.mail;

import org.junit.Test;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
import org.slim3.tester.ControllerTestCase;

public class MailControllerTest extends ControllerTestCase {

    @Test
    public void run() throws Exception {
        tester.start("/mail/mail");
        TweetController controller = tester.getController();
        assertThat(controller, is(notNullValue()));
        assertThat(tester.isRedirect(), is(true));
        assertThat(tester.getDestinationPath(), is("/mail/"));
    }
}


おもむろにテスト実行

で、まあ、これは
「"TweetControllerTest.java"を実行してください。テストが失敗するでしょう。なぜなら TweetController の run メソッドが null を返すからです。コントローラを以下のように変更してみましょう。 」(原文ママ)『フォームの作成』

というわけで、コントローラーをテストが通るように実装


MailController

package orz.mikeneck.mail;

import org.slim3.controller.Controller;
import org.slim3.controller.Navigation;

public class MailController extends Controller {

    @Override
    public Navigation run() throws Exception {
        return redirect(basePath);
    }
}


これでテストは通ります。

TODOをひとつやっつけた


  • メールアドレスを送ったあとに同じ画面に戻ってくる。
  • Validation Errorとなった場合に、エラーメッセージが作成される。
  • Emailは必須。
  • EmailはEmailとして妥当な文字列。

Emailは必須


次はEmailが入力されていることを検証します。
このToDoから想定されるのは、Emailが入っていない時は、
  • Emailが入力されていないとエラーメッセージが表示される。
  • 何かしらのメール用のアトリビュートがある。
  • 何かしらのエラーメッセージ用のアトリビュートがある。

画面とのアトリビュートに関する打ち合わせはデザイナーさんとお話ししてください。

ここでは、こういう感じで決まったことにします。
  • emailはアトリビュート : e_mailに入る
  • email用のエラーメッセージはアトリビュート : err_e_mailに入る

ちなみに、Slim3ではアトリビュート名にフィールド名を使う方法があるらしいですが、すいません、まだ学習が足りなくて知りませぬ。誰か教えて下しあ…orz

気をとりなおして!ハイ、ハイ、ハイ、ハイ、テスト追加


やることがきまったら早速テストを追加しましょう。

MailControllerTest

package orz.mikeneck.mail;

import org.junit.Test;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
import org.slim3.tester.ControllerTestCase;

public class MailControllerTest extends ControllerTestCase {

    // 省略

    @Test
    public void testEMailShouldBeFilled() throws Exception {
        HttpServletRequest request = tester.request;
        request.setAttribute("e_mail", "");
        tester.start("/mail/mail");
        TweetController controller = tester.getController();
        assertThat(controller, is(notNullValue()));

        assertThat(request.getAttribute("err_e_mail"), is(notNullValue()));

        assertThat(tester.isRedirect(), is(true));
        assertThat(tester.getDestinationPath(), is("/mail/"));
    }
}


テストっつたら実行でしょ


というわけで、テストを実行するとレッドになります。
いいですね。レッド。レッドたんかわいいよ、(^ω^)ペロペロ

テストを通るように実装する


じつはこれ(結構単純なんですけど)単純ではないんです。いくつかやることがあります。
  • アトリビュートe_mailに対して値が設定されていることのValidationを加える。
  • Validationの結果がエラーだったら、アトリビュートerr_e_mailにエラーメッセージを加える。

Validationについては『バリデーション』に詳しく記載されています。

というわけで、Validationを追加する。

MailController

package orz.mikeneck.mail;

import org.slim3.controller.Controller;
import org.slim3.controller.Navigation;

public class MailController extends Controller {

    @Override
    public Navigation run() throws Exception {
        Validators valid = new Validators(request);
        valid.add("e_mail", valid.required());
        return redirect(basePath);
    }
}


グ、たったの二行。すばらしいれす。

  • アトリビュートe_mailに対して値が設定されていることのValidationを加える。
  • Validationの結果がエラーだったら、アトリビュートerr_e_mailにエラーメッセージを加える。

つぎに、エラー判定を加えます。

MailController

package orz.mikeneck.mail;

import org.slim3.controller.Controller;
import org.slim3.controller.Navigation;

public class MailController extends Controller {

    @Override
    public Navigation run() throws Exception {
        Validators valid = new Validators(request);
        valid.add("e_mail", valid.required());
        if(valid.validate()){
            // TODO When valid
        } else {
            Errors errors = valid.getErrors();
            request.setAttribute("err_e_mail", errors.get(key));
        }
        return redirect(basePath);
    }
}


若干行数が増えました。しかもifとか付いているし…
まあ、気にせず(←)これでテストしてみましょう。

テストする


はい、通りますね。
というわけで、ToDoをまたひとつやっつけました。

…え、OKの場合?!、後でね(ToDoに追加する)。

  • メールアドレスを送ったあとに同じ画面に戻ってくる。
  • Validation Errorとなった場合に、エラーメッセージが作成される。
  • Emailは必須。
  • EmailはEmailとして妥当な文字列。
  • Emailが妥当な場合はエラーメッセージが作成されない。

あっ!

よく考えたら「Validation Errorとなった場合に、エラーメッセージ…」も実装されちゃいましたね。

  • メールアドレスを送ったあとに同じ画面に戻ってくる。
  • Validation Errorとなった場合に、エラーメッセージが作成される。
  • Emailは必須。
  • EmailはEmailとして妥当な文字列。
  • Emailが妥当な場合はエラーメッセージが作成されない。

EmailはEmailとして妥当な文字列。


これもテスト書きましょう。
とりあえず、ありえないEmailアドレスを設定して、エラーメッセージがあることを確認しましょう。

MailControllerTest

package orz.mikeneck.mail;

import org.junit.Test;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
import org.slim3.tester.ControllerTestCase;

public class MailControllerTest extends ControllerTestCase {

    // 省略

    @Test
    public void testEMailAddressShouldBeValid() throws Exception {
        HttpServletRequest request = tester.request;
        request.setAttribute("e_mail", "hoge");
        tester.start("/mail/mail");
        TweetController controller = tester.getController();
        assertThat(controller, is(notNullValue()));

        assertThat(request.getAttribute("err_e_mail"), is(notNullValue()));

        assertThat(tester.isRedirect(), is(true));
        assertThat(tester.getDestinationPath(), is("/mail/"));
    }
}


もちろんテストは落ちます。

Emailの正規表現


Emailとして妥当というのは、う~ん、難しいですね。
こういう場合はネットで正規表現パターンを探してきましょう。

^([a-zA-Z0-9])+([a-zA-Z0-9\._-])*@([a-zA-Z0-9_-])+([a-zA-Z0-9\._-]+)+$

こんな感じらしいです。

というわけで、Validationに突っ込みましょう。


MailController

package orz.mikeneck.mail;

import org.slim3.controller.Controller;
import org.slim3.controller.Navigation;

public class MailController extends Controller {

    @Override
    public Navigation run() throws Exception {
        Validators valid = new Validators(request);
        valid.add("e_mail", valid.required(),
        validation.regexp("^([a-zA-Z])+([a-zA-Z0-9\\._-])*@([a-zA-Z])+([0-9a-zA-Z\\._-])+[a-z]+$"));
        if(valid.validate()){
            // TODO When valid
        } else {
            Errors errors = valid.getErrors();
            request.setAttribute("err_e_mail", errors.get(key));
        }
        return redirect(basePath);
    }
}


テストをすると通ります。
これでエラーの場合は完成ですね。

後はOKパターン


  • メールアドレスを送ったあとに同じ画面に戻ってくる。
  • Validation Errorとなった場合に、エラーメッセージが作成される。
  • Emailは必須。
  • EmailはEmailとして妥当な文字列。
  • Emailが妥当な場合はエラーメッセージが作成されない。

本当はEmailが妥当な場合はデータを保存してとかになるのですが、それはServiceでテストするということにしておいてですね、ここではあくまでエラーメッセージについてやります。
(Serviceのテストはまだ勉強中…)

MailControllerTest

package orz.mikeneck.mail;

import org.junit.Test;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
import org.slim3.tester.ControllerTestCase;

public class MailControllerTest extends ControllerTestCase {

    // 省略

    @Test
    public void testEMailValid() throws Exception {
        HttpServletRequest request = tester.request;
        request.setAttribute("e_mail", "hoge@hoge.com");
        tester.start("/mail/mail");
        TweetController controller = tester.getController();
        assertThat(controller, is(notNullValue()));

        assertThat(request.getAttribute("err_e_mail"), is(nullValue()));

        assertThat(tester.isRedirect(), is(true));
        assertThat(tester.getDestinationPath(), is("/mail/"));
    }
}


で、これは何もしなくても通ります…

というわけで、完全Done!


  • メールアドレスを送ったあとに同じ画面に戻ってくる。
  • Validation Errorとなった場合に、エラーメッセージが作成される。
  • Emailは必須。
  • EmailはEmailとして妥当な文字列。
  • Emailが妥当な場合はエラーメッセージが作成されない。

所感


テストってやっぱり難しいと思いました。
特にまだまだ学習途中のフレームワーク・プラットフォームについてはかなりきついですね。
フレームワーク・プラットフォームで何がどうなる、そして何を利用することができるといったあたりのノウハウがないとテストを書くのはなかなか難しいと思います。
というわけで、学習あるのみと思いました。


0 件のコメント:

コメントを投稿