Slim3でValidationのテスト
元ネタは次のページです。
う~ん、いい感じですね
フォームを作成していい感じの値が入ってきた場合のテストの書き方と、Validationを使った場合のエラーメッセージの取得の実装方法。非常に参考になります。
では、Validationのテストを行っていい感じでない値が入ってきた場合のテストをどう書こうかな?
というわけで、Validationでエラーとした場合のテストを書いてみることにしました。
簡単に設計
こんな感じの設計とテスト設計です。
そうだTODOを作成しよう
というわけで、上のストーリーにしたがって、ToDoリストを作成しましょう。
- メールアドレスを送ったあとに同じ画面に戻ってくる。
- Validation Errorとなった場合に、エラーメッセージが作成される。
- Emailは必須。
- EmailはEmailとして妥当な文字列。
早速テストとControllerを作成
さっきの
フォームの作成を参考に、Controllerとかテストとかを作ります。
名前は
MailController
と
MailControllerTest
にしておきます。
なお、元の画面に戻したいので、
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が妥当な場合はエラーメッセージが作成されない。
所感
テストってやっぱり難しいと思いました。
特にまだまだ学習途中のフレームワーク・プラットフォームについてはかなりきついですね。
フレームワーク・プラットフォームで何がどうなる、そして何を利用することができるといったあたりのノウハウがないとテストを書くのはなかなか難しいと思います。
というわけで、学習あるのみと思いました。