読者です 読者をやめる 読者になる 読者になる

プログラミング 美徳の不幸

Ruby, Rails, JavaScriptなどのプログラミングまとめ、解説、備忘録。

続続railsのテストについて

railsでどの領域までをテストすべきかという話ではいろんな意見があります。

人によってはroutingの定義、validatesなどのモデルの機能が働いていることをテストすべきという人もいるし、railsの提供機能自体をテストするのはrails自体の責務なのだから、アプリケーションで(単にrailsDSLを使ったことに対する)テストはいらないという意見。

class User < AR
  validates_precence_of :name
end

これに対してテストがいるのかいらないのかというレベルで意見が別れるんですね。
結論から言えばケースバイケースなのですが、例えばこのnameが入っていないことで深刻な事故が起きるのならさすがにこんな単純なコードでもテストはあらゆる観点から書きます。

それか、意味的に少し大きく解釈してvalidates_presence_ofのテストでなくuserが必ずnameを持っていることのテストと考えればレイヤーをMySQLに移して、仮にアプリケーションでnameがはいらない状態ですり抜けたとしてもMySQLで期待されるエラーが起こってくれるかなどをテストするのもありでしょう。


ただ、そういう過剰な不安があるアプリケーション以外の、まぁせいぜい50万UUくらいで仮に事故が起きてもなんとか乗り切れるようなレベルの一般的なサービスであれば、サーバサイドに関しては経験上以下の2つだけテストを書けば十分だと思っています。

1. ページ遷移の受け入れテスト
2. 独自定義クラスの単体テスト

一般にこれ以外のテストって、よく書く順には

3. モデルの単体テスト
4. controllerの単体テスト
5. その他helperやroutingに関するテスト


4のcontrollerの単体テストについては昔qiitaでまとめたことがあって(共有してないけど)、rspecで書くと人によってはクソース書きがちなので(とくに9みたいなやつ)、書くなら明確なルールを持ったほうがいいでしょう。まぁcontrollerのspecといいながらも実際はrender_viewsしたときにページにエラーがないのかさくっと見られるのが嬉しいくらいのもんでした。ちなみに2年位前に書いたので今この書き方で動くかは知りません。

qiita.com

ページ遷移の受け入れテスト

これは書き方によってはcontrollerの単体テストに近いのですが、エンドツーエンドでDOMを指定して動いていくのが違います。ただこれを書けばリクエスト中のレコードの増減なども当然わかるので、controllerのテストでできることはブラックボックス(どういうインスタンス変数が作られたかとかは見えないという意味)でありながらだいたいできます。

ただし難点はフロントがjs依存しているとテスト用にjsのドライバーを入れてやる必要があるんですが、こいつの挙動が別プロセス(スレッド)となっていろいろな面倒があります。代表的なところでテストデータの扱い(トランザクションが使えない)とランダムにテストが失敗することが厄介です。


まぁ結論から言うと、jsに深く依存したrailsアプリをcapybaraでテストするのは諦めてちゃんとマニュアルテストしてリリースしたほうが早いと思います。

独自定義クラスの単体テスト

僕がモデルの単体テストいらないといってるのは、モデルに複雑なサービスロジック等が入り込んだらそれは別クラスとして分けるべきだろうという前提があります。

class User < AR
  def about_html
    processor.output
  end
  
  def processor
    UserAboutRichTextProcessor.new(about_text)
  end
end

class UserAboutRichTextProcessor
  def initialize(text)
    @text = text
  end

  def output
    # ここで@textを成形してリッチテキストにするコードを書く
  end
end


こういうのはさすがにこのシンプルだけど重要な責務を持つクラスをテストしたほうがいいと感じています。とくにoutputのロジックが複雑な場合は必須です。


とまぁ僕のrailsのテストの感覚ってこんなとこなんだけど、どうなんだろう? いろんなサービス運営のノウハウから自分はこういう結論になってますみたいなやつ、もっとみたいな。