TLTR;
コントローラースペック: コントローラー内部の特定のロジックと実装を検証し、ユーザー体験とは多少距離があります。
リクエストスペック: HTTPリクエストからレスポンスまで全体のユーザーフローを検証し、実際のユーザー体験を反映します。
なぜリクエストスペックが推奨されるのか?
Railsでリクエストスペックが推奨される理由を理解するために、まずRailsのリクエスト処理の流れを見てみましょう。
ステップ 1: HTTPリクエストの受信
ユーザーがブラウザでURLを入力すると、HTTPリクエストがウェブサーバー(Puma, Unicornなど)に届きます。
ステップ 2: Rackミドルウェアの処理
HTTPリクエストを受け取ると、Rackがこれを標準化し、セキュリティ、ログ記録、キャッシング、セッション管理などの定義されたRackミドルウェアを順次実行します。
ステップ 3: ルーター処理
Rackミドルウェアを通過したリクエストは、Railsルーターに渡され、適切なコントローラーとアクションが決定されます。
ステップ 4: コントローラーアクションの実行
ルーターがURLとメソッド(GET, POSTなど)に応じてリクエストを処理するコントローラーとアクションを特定すると、Railsはそのコントローラーアクションにリクエストを渡します。
ステップ 5: コントローラーロジックの処理
コントローラーはアクションを通じてリクエストデータを受け取り、必要な処理を行い、結果をビューに渡して最終的なレスポンスを生成します。
ステップ 6: 実際のHTTPレスポンスの返却
コントローラーで生成されたレスポンスは再びRackを通じてウェブサーバーに戻り、最終的にユーザーに届けられます。
この流れは、ユーザーが実際にサービスを使用する際のステップを構成しています。したがって、テストも実際のユーザー体験に近い環境で行うことが効果的です。
コントローラーテストは上記のステップのうち4~5のみに焦点を当て、コントローラー自体を検証するため、ユーザーが体験する流れの一部だけをテストします。対してリクエストテストはすべてのステップを含み、ユーザー体験の全体を検証するため、よりユーザー視点に適したテストと言えます。
「コントローラーで設定されるインスタンス変数をテストするのは良くないアイデアです。テストが知るべきことを大幅に超えてしまいます。クッキーやHTTPコード、ビューの見た目、データベースへの影響などをテストするのは良いですが、コントローラーの内部動作をテストするのは良くありません」 – DHH
DHHの意見では、テストはコントローラーの内部ではなく、実際のユーザー体験に焦点を当てるべきだとしています。コントローラーテストは内部構造の依存性が高く、テンプレートファイル名の変更などでテストが破綻しやすくなります。
そのため、Rails 5以降ではRailsチームやRSpecチームもリクエストテストを推奨しています。
結論
コントローラーテストとリクエストテストの違いは、検証範囲とユーザー体験にどれだけ近いかが中心です。コントローラーテストはコントローラー内部ロジックに重点を置き、特定のインスタンス変数やレンダリング動作に依存しやすく、ユーザー視点とは直接関係がありません。一方、リクエストテストはHTTPリクエストからレスポンスまでの全体を検証し、より現実的で信頼性の高いテストを提供します。
結論として、コントローラーテストは実装に集中し、リクエストテストはユーザー観点で全体のリクエストフローを検証するという点が大きな違いです。