2009年12月8日:サンプルコードを現在のバージョンで動作するよう修正しました。
一行掲示板を移植してみよう
連載の1回目では、Mojoのスタンドアロンサーバを使って簡単な画面を表示してみました。今回は簡単なCGIをMojoに移植しながら、リクエストの扱い方やテストの仕方を見ていきましょう。
まずはこれから移植していくCGIのソースを掲載します。あきらかに穴だらけのものですが、そこはひとまず目をつむってください。
最後のヒアドキュメントのなかにPerlの式を埋め込むテクニックはあまりなじみがないものかもしれません。詳しくは竹迫良範さんがJPerl Advent Calendar 2008に寄稿された記事[1]をご覧ください。
書き直すのはリクエストとレスポンスだけ
さて、これをそのままMojoで書き直してみます。
まずは連載1回目と同じく、Mojoをインストールしたディレクトリに新しいひな形を用意しましょう。
続いて、lib/SimpleBBS.pmの中身をこう書き換えます。
連載第1回でも説明した通り、全体がhandlerというサブルーチンの中に記述されていることを除けば、変わったのはCGIオブジェクトのかわりに$tx->reqからアクセスできるMojoのリクエストオブジェクトが使われていることと、出力部分が$tx->resからアクセスできるレスポンスオブジェクトに格納されていることだけです。簡単ですね?
リクエストオブジェクトの中身
このリクエストオブジェクトの正体は、Mojo::Message::Requestのインスタンスです。ここにはさまざまなメソッド、オブジェクトが格納されていますが、ふだんよく使うのはこのくらいでしょうか。
- $tx->req->param(パラメータ名)
クエリストリングやフォームデータのパラメータを返します。
- $tx->req->method
リクエストのメソッド(GET、POSTなど)を返します。
- $tx->req->is_multipart
リクエストがマルチパートのフォームデータかどうかを返します。
- $tx->req->cookie(クッキー名)->value
クッキーの値を返します。
- $tx->req->headers->content_length
Content-Lengthヘッダの値を返します。
- $tx->req->headers->content_type
Content-Typeヘッダの値を返します。
- $tx->req->headers->header(ヘッダ名)
任意のヘッダの値を返します。
- $tx->req->url->path
PATH_INFOの値を返します。
- $tx->req->upload(パラメータ名)->file->move_to(移動先)
アップロードされたファイルを移動します。
そのほかのメソッドや、各メソッドの詳細については該当するクラスのPODやソースコードをご覧ください。
CGIとして動かしてみる
さて、このSimpleBBS、連載第1回のように開発用のスタンドアロンサーバで動かしてもよいのですが、お手元にApacheなどのサーバがあるならCGIとして動作させてみましょう。
本当はシェル(コマンドライン)から「perl script/simple_bbs cgi」を実行するとCGI向けの出力が得られるのですが、この形ではブラウザから実行しづらいので、別に起動スクリプト(index.cgi)を用意します(use libの中身はお手元の環境にあわせて適宜修正してください)。
サーバの設定ファイルにCGIの実行権限を追加して再起動したら、ブラウザからいまのCGIを実行してみてください。送信したテキストがテキストボックスの下に表示されていけばひとまず成功です。
テストを書こう
ところで、最初にお断りしたように、このCGIにはいくつもバグがあります。たとえば、テキストボックスから半角の0を送信してみてください。本当は0というテキストが追加されるべきなのに、なにも起こらなかったはずです。
このような場合、みなさんならどうするでしょうか?
この程度の分量であれば、いきなりソースコードを見ても問題なく直せるでしょう。でも、コードがもっと複雑になってきた場合、そして同じようなフォームがたくさんある場合、いきなりコードに手を入れるのは下策です。ここでやってしまったケアレスミスをほかのところで繰り返さない保証はないのですから、せめてテスト項目に加えておくべきですし、できれば自動的にテストできるようテストコードを書きたいところです。
ウェブアプリケーションをテストする場合、一般的にはWWW::Mechanizeのようなモジュールを使って本番環境と同じ動作をする検証用アプリケーションにアクセスし、フォームに値を入れたりリンクをたどったりしていくのが常道ですが、Mojoの場合、テストにあたってわざわざ検証用の環境を構築する必要はありません。たとえば、0に対するテストであれば、このように書けます。
テストを実行してみる
このテストをt/false_value.tという名前で保存したら、実際にテストを走らせてみましょう。シェル(コマンドライン)からこのようにタイプしてください。
いまの段階では当然テストは失敗します。問題の箇所を修正しましょう。差分はこうなります。
テストは正常に見えるバグも見つけてくれます
これでブラウザからは直ったように見えますが、ふたたびテストを実行してみると、まだミスが見つかります。
改行が落ちていなかったのですね。
これでひとまずt/false_value.tのテストは通るようになりました。めでたしめでたしと言いたいところですが、このテストデータはいったいどこに保存されていたのでしょうか?
設定は外から変更できるように
テストを実行したときに、前のテストデータが残っていては正しいテストにはなりません。データファイルの設定は外から変更できたほうがよいでしょう。
このような場合、アプリケーションのコンストラクタに環境依存の設定を渡せるようにするのが常道ですが、ここではあとからデータファイルを操作することが予想されますので、アクセサ/ミューテータを用意することにします。
lib/SimpleBBS.pmの差分はこのようになります。
t/false_value.tの方も修正しましょう。
これで何度テストを実行しても、古いデータでテストしたり本番環境のデータを壊したりすることはなくなりました。
同じ要領でt/xss.tを書いて、XSS(クロスサイトスクリプティング)のバグもつぶしておいてください。
Mojoを使うと、アプリケーションが自然にサーバ環境に依存する部分とそうでない部分に分かれていきます。アプリケーションと各種サーバを結びつける部分はMojoのほうでテスト済みですから、わさわざ自分でテストする必要はありません。どのような環境でも変わらない、アプリケーション本体だけをテストすればよい――そのような責任の分担が、Mojoを使う大きなメリットのひとつです。
次回は画面遷移のあるもう少し複雑なアプリケーションに挑戦してみます。お楽しみに。