Blog

Testing Web Application 2011秋

最近の僕のテスティングな日々についてまとめておきますよ。

【前提】

テストの目的

俺がつくった部分を他の誰かがぶっこわさないかどうかを監視する

テストかいてなくてエッジケースで他の誰かがちょっと変更してぶっこわれたりするとダルいですよね。ここでいう他の誰かというのは未来の自分も含みます。

なんども手でうごかすのがダルい部分の処理を自動でテストしたい

たとえば API まわりとかそういうのです。ちょっといじってはブラウザでポチポチやるとか、だるい! ってなります。

とにかく楽に、お気軽に。

お気軽にテストを追加できて、お気軽にテストを実行できる。というのがなによりも重要です。

追加しようとおもったときに「どう追加したらいいかわからない」という状況になりがちなので、あらかじめいろいろな構成要素ごとにテストをひととおりかいてみるというのも重要だとおもいます。O/R Mapper のクラスのテストとか、model のテストとか、コントローラのテストとか、JSON API のテストとか。。

Ukigumo をつかった CI

Ukigumo を開発環境でうごかしています。これで、誰かがテストをぶっこわしても安心です。だいたいチームの人数がふえてくると、テストをうごかさない人もでてきますし、自分でも毎回すべてのテストをうごかしているわけではありません(時間かかるから)。

ちなみに現在のテストのフル実行にかかる時間は36秒です。

ExtUtils::MakeMaker でテストをうごかさない

ExtUtils::MakeMaker を素でつかうと blib/ とかつかってきてうざいので、Makefile.PL に以下のような hack をほどこしてあります。ウェブアプリケーションで blib/ とかにコピーする必要ないですよね。実運用でも blib/ でうごかさないし、インストールもしませんし。

# 素の make test つかうと blib/ にコピーされたりしてうざいので prove 直接たたいてやります
sub MY::test_via_harness {
        "\tprove -r t"
}
# pm_to_blib とか余計なファイルつくらせないようにするためのおまじない
sub MY::top_targets {
        <<"..."
all ::
\t
pure_all ::
\t
subdirs ::
\t
config ::
\t
...
}

DB は開発環境のものをピーコしてつかう

mysqladmin -uroot create myapp
mysqldump -uroot -d myapp-dev | mysql -uroot myapp

するかんじがいいですね。Test::mysqld などをつかってもいいんですが、いかんせんテストの起動がおもくなってしまいます。

make test の間で一回しかうごかさない、みたいな hack もあるとおもいますけども、開発環境ではすでに mysqld たちあがってるから別個にたてる必要性が皆無ですよね、ってかんじです。

prove をつかいこなす

.proverc に以下のようなかんじでかいてます。 App::Prove::Plugin::SchemaUpdater っていう prove のプラグインをある人がかいていて、それがインテリジェントに開発環境の schema 構成を、テスト用のデータベースにピーコします。本当は schema をちゃんと管理したほうがいいんですが、schema ファイルをアップデートせずにいきなり ALTER うちこむ人などが多発しがちなので、こういうかんじでやっつけています。

"--exec=perl -Ilib -I. -Mt::Util"
--color
-Pt::lib::App::Prove::Plugin::SchemaUpdater

t::Util を充実させる!

テストを書くときって、まずどうやってかいたらいいのかわからないっていうのがあるとおもうんです。だから、いろいろがんばるというのが肝要です。

たとえば、テスト用の user データをつくる、みたいなのって頻出パターンだから、

my $user = create_user(name => 'John');

みたいなかんじで、ちゃちゃっとつくれるようにしておくというのが重要です。いまやってるやつだとこういう感じのメソッドが8つぐらいあります。

mock_http() みたいな関数をつくる!

LWP::UserAgent をモッキングする LWP::Protocol::PSGI っていうのがあるんですけど、これつかうと全部 PSGI のハンドラで処理しなくちゃいけなくて、元の LWP へアクセスをながすみたいなのができなくて不便なので、手で hack したクラスををつくってます。

mock_http(); ってやると、サービスの URL だけをフックして、*.psgi をコールします。これで、普通に LWP::UserAgent や Test::WWW::Mechanize などをつかって気軽に HTTP based testing が可能となります。

まとめ

お気軽にテストを追加して、安心して開発ができる環境をつくることについてかんがえてみました。