« つくるぶガイドブログ スタート!! | メイン | Ruby on Rails を使ってひとりでサービスを作ってみよう »

Test::WWW::Declareで宣言的にWebアプリをテストはてなブックマークに追加 livedoorクリップに追加 Yahoo!ブックマークに追加 del.icio.usに追加 イザ!ブックマーク ニフティクリップに追加

こんにちは。
つくるぶガイドブログ Perl担当の西山です。

Perlカテゴリーのエントリーでは、CPAN(世界中のPerlプログラマーが作成しているライブラリを集約したアーカイブ)に登録されているモジュールの中から、便利だったりコードが格好良かったり、Perlならではの魅力を持っているようなモジュールを取り上げていこうと思っています。
よろしくお願いします!

Test::WWW::Declareモジュールについて

というわけで、一発目は Test::WWW::Declare モジュールをご紹介します。

今年の春のYAPC::AsiaでJesse Vincent氏が 「Abusing Domain Specific Languages for Fun and Profit」 というセッションで発表していたり、最近では 宮川達彦さんのWeb::Scraperのスライド
"integrate with WWW::Mechanize and Test::WWW::Declare"
と書かれていたりで気に留めていた方も多いんじゃないでしょうか?しばらくSubversionのリポジトリでしか公開されてなかった様ですが、先月末ようやくCPANにアップされました。

Test::WWW::Declareは、Webアプリケーションのテストコードを宣言的に記述する為のモジュールです。「宣言的である」ということは、作業そのもの(HOW)を記述するのでは無く、性質や状態を定義することで「それは何なのか(WHAT)」という観点で対象を記述するようなイメージでしょうか。

このモジュールでは、Perlの持つ機能を駆使して英語に近い構文のDSLを定義することで、宣言的なコーディングを実現しています。内部的にはテスト用のモジュールとして実績のある Test::WWW::MechanizeとTest::More をラッピングする形で実装されています。

また、Railsの対抗馬として開発されていると話題になっているWebアプリケーションフレームワークJiftyと開発元が一緒ということもあって、Jiftyとの連携も念頭に開発されているようです。

インストール

通常通りcpanコマンドから install Test::WWW::Declare と実行してインストール・・・と行きたいところですが、現状ではコマンド経由でインストールできないようなので、tar.gzファイルを直接取得してインストールします。Linux系では以下のコマンドをシェルから実行してください。
% wget http://search.cpan.org/CPAN/authors/id/S/SA/SARTAK/Test-WWW-Declare-0.01_01.tar.gz
% tar xvzf Test-WWW-Declare-0.01_01.tar.gz
% cd Test-WWW-Declare-0.01_01
% perl Makefile.PL
% make
% make test
% sudo make install

機能概要

では、簡単なサンプルを用意しましたので、どんなモジュールなのか見てみましょう。 Googleで「つくるぶ」をキーワードに検索した後、検索結果につくるぶのサイトが表示されていることを確認し、 リンクをクリックしてつくるぶが表示されることを確認するテストプログラムです。
#!/usr/bin/perl

use strict;
use warnings;
use utf8;
use Encode;

use Test::WWW::Declare tests => 2;

session 'test_tkrb' => run {
    my $g_enc = find_encoding('shiftjis');
    my $t_enc = find_encoding('eucjp');

    # Googleでつくるぶを検索する
    flow 'search' => check {
        get 'http://www.google.co.jp/';
        fill form 'f' => {
            q => $g_enc->encode('つくるぶ'),
        };
        click button $g_enc->encode('Google 検索');

        content should contain $g_enc->encode('<b>つくるぶ</b> の検索結果');
        content should contain 'http://www.tkrb.jp';
        content shouldnt contain $g_enc->encode('<b>つくるぶ</b>  に一致するページは見つかりませんでした。');
    };

    # 検索結果からつくるぶに遷移する
    flow 'go_tkrb' => check {
        my $pattern = $g_enc->encode('^つくるぶ');
        click href qr($pattern);
        content should contain $t_enc->encode('つくるぶ');
        content should contain $t_enc->encode('このサイトについて');
        content should contain $t_enc->encode('ガジェットチュートリアル');
    };
};

何だかPerlのコードに見えない箇所もありますが、特に click href ~ とか content should contain ~の辺りはそこまでやるかっていう涙ぐましいまでの執念を感じます。正に英語で動作仕様をそのまま記述しているようなシンタックスです。Perlが持つ言語仕様の柔軟さ、拡張性の高さの一端を感じ取れますね。

コード中のsessionは、ブラウザとWebサーバの間のセッションと対応します。ユーザ一人あたりの振る舞いと考えると分かりやすいかもしれませんね。内部的には1つのsessionに対して1つの WWW::Mechanize のインスタンスが割り当てられるようです。

1つのsessionの中には動作のまとまりを表すflowを複数定義することができます。そしてflowは、フォームに値を入力 (fill form) やボタンクリック (click button) などのアクションと、画面に特定のものが表示されるか? (content should contain) などの事前/事後条件から構成されます。どういう条件の時に画面をどう動かすとどうなるか?を記述するイメージ。

session、flowという概念によってテストコードが意味のある単位で括られているおかげで、テスト仕様としての可読性が高くなっていると思います。

DSLスタイルのコーディングの参考として

さてさて、ここまで説明して来ましたが、バージョンが0.01_01なことからも察することができるように、実際のところいきなり実務レベルで使うのはまだ難しいと思います。単体ではまだステータスの確認など細かい条件設定はできないようですし、API自体まだ変更される可能性はあります。

ただ、まだ開発レベルでコードの規模が小さいことを逆に考えると、このTest::WWW::DeclareはPerlでDSLのスタイルでモジュールを書く方法を学ぶのに恰好の素材なんじゃないかなと思いました。PODを除くと300行強と全体の見渡しもいい感じ。一部_magic_matchとかいうややこしい処理を集約した関数はありますが、Perlのプロトタイプを駆使してDSLチックな関数を実現しているのが分かりますね。

まとめ

Webアプリのテスト仕様を宣言的に記述し、実行できるようにするTest::WWW::Declareモジュールをご紹介しました。まだまだ開発途上ですが、JiftyやWeb::Scraperなどの他のアプリケーションとの連携も含めて今後注目していくと面白いと思います。また、PerlでDSLのスタイルでモジュールを作成する際の参考としてもオススメです。