Selenium IDE で生成したテストケースに従ってWWW::Mechanizeを動かすためのラッパーモジュールMechanizedSelenium(仮称)を作ってみて、どれくらい使えるか試してみました。
一度、ウェブアプリケーションのテストをするために HTTP::WebTest を使ってテストケースを書いたことがありました。しかし、ブラウザをマウスでちょこっとつつくだけの動作をperlで書き直すのは本当に退屈な作業ですし、テストケースを書くこと自体が困難で、アプリケーションにバグはないのにテストケースにバグがあるせいでテストがこける、ということもしばしばでした。
そんなところにやってきた Selenium IDE は、ブラウザでテストしたい機能をマウスでつついていくだけでテストケースが作成され、テストケースを作る作業を100倍くらい効率的にしてくれた画期的なツールです。出会ってしばらくはテストケースを動かすのが楽しくてテストケースばかり作っていました。
もうひとつ、蛇足ですが Yahoo! Pipes も、やりたいことはアタマの中ではっきりとわかっていて、作るのは難しくないはずなのになんかめんどくさいフィードの加工をかんたんにできてしまうところに、同じ種類の感動を覚えました。
これらのみっつのツールは、立体をどの平面で切り取るかによってかたちが変わるのを連想させます。切り取る平面によって、切り取られてできた二つの立体の接合面は大きくなったり、小さくなったり、複雑なかたちになったり、シンプルなかたちになったりします。同じように、なにか作りたいものを、どういう視点で切り取るかによって、かんたんか、難しいか、めんどくさいか、すぐにできるか、が変わってくる、のだと意識するようになりました。
すごく手間がかかっていたことが、かんたんにできるようになることほど楽しいことはありません。
そのとき Perlモジュール/WWW::Mechanize - Walrus, Digit. を見て、モジュールのメソッドがjavascriptに近い気がして、そして"かんたんなことをかんたんに"ルールを思い出しました。javascriptのコードに似ているということは Selenium IDE の吐き出すコードでWWW::Mechanizeをドライブできるはず。
というわけで Perlモジュール/WWW::Mechanize - Walrus, Digit. に載っている mixiへの日記の投稿 をためしにやってみました。
use strict;
use warnings;
use Time::HiRes qw(sleep);
use Test::WWW::Selenium;
use Test::More "no_plan";
use Test::Exception;
my $sel = Test::WWW::Selenium->new( host => "localhost",
port => 4444,
browser => "*firefox",
browser_url => "http://localhost:4444" );
$sel->open_ok("/");
$sel->type_ok("email", "myaddress\@example.com");
$sel->type_ok("password", "password");
$sel->click_ok("sticky");
$sel->click_ok("//input[\@type='image']");
$sel->wait_for_page_to_load_ok("30000");
$sel->click_ok("menu3");
$sel->wait_for_page_to_load_ok("30000");
$sel->click_ok("//input[\@value=' 日 記 を 書 く ']");
$sel->type_ok("diary_title", "MechanizedSelenium初日記");
$sel->type_ok("diary_body", "SeleniumIDEとWWW::Mechanizeを使って、perlから簡単に日記を投稿するテストです。");
$sel->click_ok("//input[\@value=' 確認画面 ']");
$sel->wait_for_page_to_load_ok("30000");
$sel->click_ok("//input[\@value=' は い ']");
$sel->wait_for_page_to_load_ok("30000");
このコードはSeleniumをリモートのマシンから動かしてテストする Test::WWW::Selenium モジュールのためのコードになっているので、これを解釈するためのラッパーを用意する必要があります。
Test::WWW::Selenium のメソッドをハンドルして WWW::Mechanize を動かします。SeleniumがHTMLのエレメントを指定する書式がXPathと同じだったり違ったりするのをHTML::TreeBuilder::XPath などを使って吸収したり、文字コードの変換をしたり、METAタグのRefreshをサポートしたりしています。
MechanizedSeleniumを使ってmixiに日記を投稿してみましょう。
自分でMechanizedSeleniumオブジェクトを生成するコードを書いたら、あとははじめに Selenium IDE で生成したスクリプトから、操作を表している部分を切り取って貼付けます。
ひとつだけ注意点があります。スクリプトの文字コードはUTF-8で書いて、でも use utf8 はつけないでください!(このへんいまだによくわかっていないため、つけると動かなくなります....)
できあがったコードはこんなかんじになります。
#!/usr/bin/perl
use strict;
use warnings;
use MechanizedSelenium;
my $sel = new MechanizedSelenium();
$sel->baseurl("http://mixi.jp/");
$sel->open_ok("/");
$sel->type_ok("email", "myaddress\@example.com");
$sel->type_ok("password", "password");
$sel->click_ok("sticky");
$sel->click_ok("//input[\@type='image']");
$sel->wait_for_page_to_load_ok("30000");
$sel->click_ok("menu3");
$sel->wait_for_page_to_load_ok("30000");
$sel->click_ok("//input[\@value=' 日 記 を 書 く ']");
$sel->type_ok("diary_title", "MechanizedSelenium初日記");
$sel->type_ok("diary_body", "SeleniumIDEとWWW::Mechanizeを使って、perlから簡単に日記を投稿するテストです。");
$sel->click_ok("//input[\@value=' 確認画面 ']");
$sel->wait_for_page_to_load_ok("30000");
$sel->click_ok("//input[\@value=' は い ']");
$sel->wait_for_page_to_load_ok("30000");
これを実行すると、ブラウザでの操作を Selenium IDE が記録した通りの動作をエミュレートして日記が投稿されます。
WWW::Mechanizeで再現させるためのラッパーを作ってみました。Selenium IDE とWWW::MechanizeをMechanizedSeleniumで組み合わせることで、視覚的に、かんたんにAPIもどきを作ることができます。
Selenium IDE の生成するエレメントの選択ルールは単純なのでうまくエレメントが選択できなかったり、ターゲットとしているサイトのHTMLが壊れているためHTML::TreeBuilder::XPathでうまくマッチできなかったり(今回TABLEタグの直下にFORMタグが挟まっていて、そのあとにTRが書かれていたためにうまく動かないところがありました)、最近のjavascriptでばりばり動くサイトには無力だったりしますが、サービスによっては十分有効なアプローチになるはずです。
現状ではとりあえず日記が投稿できるようにしたレベルの実装ですが、ほかでも使えるようにしていこうと思います。
関係ないですが、そんな画期的な Selenium IDE を作られた方が第6回オープンソーステクノロジー勉強会でお話されていたのをさっき知りました。作った動機とかお聞きしたかったです....
*
ちょこっと調べたら perl.com: Web Testing with HTTP::Recorder なるものが既にありました。こちらはHTTPのProxyとして動作して、ブラウザから送られてきたリクエストを記録することでWWW::Mechanize用のコードを生成するものです。最終的に送られるデータを解析してコードを生成するアプローチの方が実装がシンプルになるのでHTTP::Recorderのほうが断然よいです....
トラックバック元エントリにこのエントリへのリンクがない場合はトラックバックを受け付けません。
http://labs.gmo.jp/mt/mt-tb.cgi/121
comments