2006/10/25 (水)
■ Test makes hackers also happy

『WEB+DB PRESS Vol.35』:実演! テスト駆動開発 - 角谷HTML化計画(2006-10-24)
TDDはハッカーのための技術ではない。ハッカーにTDDは要らない。ただただハックすればよい。偉大なプログラマは偉大なプログラミングをすればよい。だが、ハッカーならぬ凡百たる私のような"普通の"プログラマはそうはいかない。TDDは我々が日々の仕事に自信を持ち、誇りを持って定時に帰るための思想だ。
言わんとすることは理解できる(つもりだ)けど、TDD こそハッカーのための技術(でもある)、という気がしないでもない。
Pugs (Perl6) も JSAN も Perl ハッカーのはじめた新しい言語・ライブラリのレポジトリなんだけど、そこで一番最初にポーティングされたモジュールが Test::Simple (Test::More) だった、という事実に注目しないと。
#perl6 や Pugs のMLで「このコードはこういう挙動でいいの?」と質問すれば「commit bit あげるから .t (テストコード)にしてコミットしておいてよ」といわれる。
Plagger も最初こそテストかかずにやってきたけど、いまやテストかかずにプラグインコミットするのは健康に悪い。tools/plugin-start.pl で勝手にテストの雛形がつくられるようにしたのもそういう理由。
たぶん。彼らは怠惰だ。短気だ。傲慢だ。だが、少なくとも私には怠惰が足りない。怠惰が足りないプログラマの仕事をドライブするものこそテストだ。私は毎日が不安だ。
ハッカーは怠惰だからこそ、自分で結果をチェックするなんて面倒くさいことをせず、テストコードにそのチェックをやらせるんじゃないかな? 「楽をするためならどんな苦労もいとわない」のがハッカーでしょ。
■ Test::Base driven Development

404 Blog Not Found:テキストエディタさえあればできるTDD
まあいわんとすることはわかるのだが、例がわるくて Perl のほうがぜんぜん簡単に見えないし、TDD のポイントは Test を書いてインタフェースを決め、fail させ、実装コードを書いて pass させるという点にある(と思う)から、コード使いでない人がかける云々というのはポイントではないはずだ。
それにいくら Perl を贔屓目に見たところで、実際の実装コードとテストコードを違う言語で書くことにメリットはほとんどないはずだから、ここでも Java は見にくくて云々は関係ない。
ついでなので、Test::Base でテストを書くとこのようになる。Lingua::JA::Hepburn::Passport (入力されたひらがな・カタカナをヘボン式ローマ字に変換)を例にすると、
use strict;
use Test::Base;
use Encode;
use Lingua::JA::Hepburn::Passport;
sub hepburn {
Lingua::JA::Hepburn::Passport->new->romanize( decode_utf8($_[0]) );
}
filters {
input => [ 'chomp', 'hepburn' ],
expected => [ 'chomp' ],
};
run_is 'input' => 'expected';
__END__
===
--- input
なんば
--- expected
NAMBA
===
--- input
ほんま
--- expected
HOMMA
===
--- input
さんぺい
--- expected
SAMPEI
===
--- input
はっとり
--- expected
HATTORI
===
--- input
きっかわ
--- expected
KIKKAWA
===
--- input
ほっち
--- expected
HOTCHI
===
--- input
はっちょう
--- expected
HATCHO
===
--- input
こうの
--- expected
KONO
===
--- input
おおの
--- expected
ONO
===
--- input
ひゅうが
--- expected
HYUGA
===
--- input
ちゅうま
--- expected
CHUMA
===
--- input
おーの
--- expected
ONO
=== Katakana
--- input
チュウマ
--- expected
CHUMA
真ん中にある __END__ の上がテストコード、下がそれに食わせるデータである。いわゆる MVC とかでデザインとロジックの分離!とか言うが、テストにおけるテストコードとテストデータの分離、といってもいいかもしれない。
Test::More では .t にのっぺり書いていくのがいや、という人も Test::Base ならこのようにかけて安心。「結局__END__ 上のテストコード(フィルタとか)は .t ごとに書くんじゃねえの」という方は、t/MyTest.pm とか書いて .t からは use t::MyTest; と呼び出せば再利用できる。
というわけで自分が CPAN モジュールを書くときは、
- モジュール名決める
- pmsetup で雛形作成
- APIを決めて、POD を書く
- t/01_module.t にテストコードとテストデータを書く
- make test こける
- 実装
- make test OK
- コーナーケースのデータを .t に追加
というようなサイクルで実装してます。
コーナーケースの発見がたまに難しいわけだけど、それに注目しているのが LectroTest という仕組み。Haskell では QuickCheck, CPAN には Test::LectroTest とかあるが、ちょっと test spec の作り方が難しそう。うまいこと Test::Base にフィードするデータをこんな感じでつくれると回帰テストに役立ちそうだなんだけど。