ずっとテストのあるWebアプリケーション眺めてるのでだんだんコツが分かって気がする。まず最初にCIに載せて、カバレッジ測れるようにする。面倒だけど、これやっておくと後で役立つ。普通にテスト書くと、実行環境までは定められないけど、CIがあれば、そこをベースに議論できる。最初は、アプリケーションのルートのモジュールをuse_okするだけ、くらいでまず通して、カバレッジも取れるようにする。たとえば、MyAppっていうアプリケーションなら、use_ok MyAppするだけ。これだけでもなかなか大変で、テストコードからロードパス通したり、テストに使うライブラリ何にするかとか、手元なら適当にライブラリ入れればいいけど、CIで動かすためには何らかの構成管理がされてないといけないとか、いろいろある。オープンソースならTravis CIとか、社内にJenkinsあったり、お金払ったらcircl CIとか、Ukigumoっていう謎のPerlのプロダクトとか、いろいろある。あとPerlだとテストに日本語書くとWide characterになって怒られるのでちまちまなんかするっていう伝統行事もある。いろいろあってそれができたら、全てのモジュールがコンパイルできるっていうのを書いてみる。ここでこけたら依存関係の管理とかがおかしい。cpanfileとか直すことになる。それができたら、ようやくテスト書いていけるので、一般的なユースケースとかを書いてみる。Plackを使ったWebアプリケーションだったら、Plack::Testとか使うと簡単。1リクエストのやりとりを簡単に書ける。こうするとcookieもらえてこうするとこう、みたいなインタラクションを書きたかったらMechanizeとか使うと書きやすくて、もうちょっとなんとかする必要がある。いつも触ってるプロダクトでは、通信結果をCSSセレクタでDOMに触れるようになってて便利。本当はずるいけどユースケース書くときにも軽くカバレッジ見ておくと、こういうパターンとこういうパターン、みたいに書いていける。本当はブラックボックス的に仕様だけを書けるといいけど、ぶっ壊れてるアプリケーションの仕様とか知らないから、まずはカバレッジを高めて、一通りの仕様を知ることを優先した方が楽。それで、一通りのリクエストとレスポンス試せたら、その裏にいるモデルとかドメインのテストとかを書ける。ここに来るまでにカバレッジ高めておければ、どのコードもそこそこテストコードから呼ばれてるはずなので、ぼちぼちリファクタリングとかできる。僕はC0 100%にしたい派なので、die "not implemented";みたいなメソッドもとになく呼んでカバレッジ高めたり、どうせ死ぬんだからdieするだけのコードごと消してしまったりしてる。
変な事例だけど、今日見てたコードは、同じ機能の実装が二箇所に別々にあって、そのうち片方はどうがんばってリクエストを送信しても到達できないことになってた。カバレッジレポート見たら気づけた。現実的なアプリケーションで、全ての実行パスを把握している人はあまりいない。いろんな人がテストないまま触ってるとこういうことも起きるので、テストとカバレッジレポートは必要。テスト、一度書いてしまえば役立つ。どこ触っても落ちるようなテストは、落ちることがわかってから捨てて書き直せばいいので、どんどんテスト書いていきたい。
今日はテストないところ触ってたけど、いつもはテストあるコードを触っていて、テストあると、変なことするとすぐ落ちるのですごく楽になってる。それでも十分なわけではなくて、特定の条件でおかしくなる事例などがあって、このへんはC0 100%ではだめで、C2 100%が必要だから困った、とかそういうことを話してたりする。早く銀の弾丸拾いたい。