tokuhirom's blog.

'; DROP DATABASE database();

Shipped File::Zglob 0.01

http://github.com/tokuhirom/File-Zglob

File::Find::Rule とかまあ結構なんですけども、

File::Find::Rule->file->in('lib')->name('*.pm')

っていうフォームはなかなかぱっと思いだしづらいです。ユーザーフレンドリーじゃないんですね。

シェルだったら lib/**/*.pm ってうったらいっぱつででてくるじゃないですか。そういう風にうちたいですよ。

というわけでつくってみました。 File::Zglob です。

use File::Zglob;
my @files = zglob("lib/**/*.pm");

という風にうつだけでいいんです。このインターフェースならわすれないでしょう。shell で普段からうってますものね。

ちょっとしたスクリプトとかで超便利だとおもうので、ぜひつかってみてください。

【速度】
PP で実装されている関係上、glob や bsd_glob より遅いですが高機能でカジュアルにつかえるので問題ないかとおもいます。File::Find::Rule よりは速いですし。

【余談】
gauche の sys-glob を移植しています。そのおかげでコードがやたら関数型っぽくなってしまっていますがそのうち整形してもいいかなとおもっています。

【余談2】
このモジュールつくりたいとおもってからかれこれ3年ぐらいたってしまいました。赤坂ツインタワーの地下でかずほさんがこういうのあったらいいねーっていう話をしていたのがきっかけでつくりたいとおもってた気がするのでほんとにだいぶ前です。

だいぶねかせてたわりに3日ぐらいでできあがりました。一番時間がかかったのは gauche の関数名をググる作業です。

【余談3】
最初はPerl本体にくみこもうとおもってたんですが、いかんせん本体のコードは OpenBSD 由来の C コードなのでいじりづらかったんですね。どうやったら ** の処理とかきっちりできるのかは把握したので今ならできるとおもいます。

Perl のコードになったおかげで内容が把握しやすくなったので本体の方にとりこんでもらうのはわりと誰でも簡単に挑戦できる気はしますけど。

Testing Web Application 2011秋

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

【前提】

  • Perl でかかれたウェブアプリケーション
  • 自社開発のウェブアプリケーション
  • 一日に何度も deploy されるレベル
  • フルテストを全員がうごかしているとはかぎらない

テストの目的

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

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

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

たとえば 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 が可能となります。

まとめ

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