Ruby on Railsのテストコード実装方針を考えた

こんにちは。つい先日、MacBook Pro 13インチを買ってワクチクしながらセットアップしている今日この頃の下條です。クリーンな環境はやはり気持ちがよいものですね。

さて、最近は会社でRuby on Railsを使うメンバーも増えてきたことだし、Railsアプリケーションでどこまでテストを書くかの大枠の認識合わせをしておこうと思い、テストコード実装方針をおおざっぱに決めた。
なお、Everyday Rails - RSpecによるRailsテスト入門を参考にさせていただいた。

ビューのテストは書かない

ビューのテストのメンテナンスは面倒である。そして、往々にしてある意味DRY原則に違反しがちである。例えばビューに設定されたスタティックな文字列を確認するだけのテストは一般的には意味はないと思う。
ただ、ビューにロジックが入ってしまい、インテグレーションテストでも担保ができない場合についてはこの限りではない。

モデルは基本的に全てのメソッドのテストを書く

モデルのメソッドのテストは全て書く。Railsの基本機能で提供されているバリデーション(存在チェック、ユニークチェックなど)、関連についてはテストは書かない。独自バリデーションを作った場合にはテストを書く。

ヘルパーは全てのメソッドのテストを書く

ヘルパーは名前空間を汚すため、できるだけ使わずDraperなどでDecoratorを使うようにしたいところではあるが、いずれにしてもテストを書く。

コントローラのテストは基本的に書かない。

まずはファットコントローラになっていないというのが前提である。

Everyday Rails - RSpecによるRailsテスト入門では基本的にはコントローラのテストを書くべきという立場をとっている。コントローラのテストを書く理由としては、以下が挙げられている。

• コントローラもメソッドを持ったクラスである。この点についてはPiotr Solnica が素晴らしいブログ記事を書いています。そしてRailsアプリケーションにおいて、コントローラはかなり重要なクラス(とメソッド)です。なので、スペック的にモデルと平等に扱うのは良い考えです。
• コントローラスペックは統合テスト用のスペックで同じ事をやるのに比べて速く書けることが多い。私の場合、この点は非常に重要です。なぜならコントローラレベルで存在しているバグに対処したり、ちょっとしたリファクタリングを検証するためにスペックを追加したくなったりすることがあるからです。堅牢なコントローラスペックを書くのは比較的単純な作業です。なぜかといえば、フィーチャスペックとは異なり、実行コストを上げずに目的のメソッドに特定の入力値を与えることができるからです。そしてこれは次のようなことも意味しています。
• コントローラスペックは通常、統合テスト用のスペックよりも素早く動作する。これはバグを直したり、異常系の操作(もちろん正常系の操作も)を確認したりする際にとても助かります。

特にコントローラテストが統合テストよりも速く実行できるというのは重要な点だと思う。ただ、コントローラスペックの方が統合テストよりも速く書けることが多いというのは若干そうでもないかなという気もする。コントローラのテストはパラメータなどいろいろと前準備が必要となり、書きにくいことも多い。
薄いコントローラになっていれば、統合テストでコントローラ部分のテストが網羅できることも多い。したがって、統合テストでコントローラ部分の動作を担保するという方針とした。ただ、コントローラに重要ロジックが入っていて、それを統合テストでテストできない場合はその限りではない。

上記以外のコード

ライブラリなどを作った場合にも基本的にテストを書く。

APIのテストについて

APIについては、コントローラにロジックが入っていてもコントローラテストは書かない。Requestスペックのみを書く。Requestスペックはテスト実行速度が速いし、コントローラテストを内包できるためである。以前、コントローラテストしか書いていないAPIがあって、ルーティングのバグを検出できなかったことがある。ルーティングを含めてテストできるRequestスペックの方がよい。

テストの順序のランダム化

テスト実行後の後始末忘れなどがあった場合に、単体では落ちるテストでも、流しでテストをするとテストの順序に依存して落ちない場合がある。これはテストのバグといえるもので、ないようにすべきものだが、テストの順序をランダム化しておけばこのような問題を検出できるようになる。何回もテストを通すと落ちることになるので。
テストのランダム化は、以下のようにspec/spec_helper.rbなどに追記。

1
config.order = "random"

また、テストを流すと、ランダムネスを作るために使用されたシード値が表示される。

1
Randomized with seed 1357

そして、出力されたシード値をつけてテストを実行すると、この時実行したテストの順番を再現できる。

1
$ bundle exec rake spec --seed 5919

以上ですが、これは違うんじゃないかとかコメントがあればいただけると幸いです。

Ruby on Railsを活用したWebサービスや業務システム開発をご検討の企業様は、是非MMMにご相談下さいませ!

このエントリーをはてなブックマークに追加