前回の続き
RSpecでのコントローラのテストはモデルのテストと統合テストで代替できてしまうため、使う機会は多くありません。
最近では、より高度な統合テストであるシステムスペックが導入されたため、コントローラスペックの出番はさらに減少しました。
とはいえ、既存のプログラムの保守で触れることもあるかと思うので、軽く触れる程度にまとめます。
#静的なコントローラのスペック
レスポンスのステータスが成功しているかをテストします。
まずは、スペックファイルの生成。
$ rails g rspec:controller home
spec/controllers/home_controller_spec.rbが生成されます。
コントローラがリクエストに対して正常なレスポンスを返すかテストします。
require 'rails_helper'
RSpec.describe HomeController, type: :controller do
de
describe "#index" do
it "responds successfully" do
get :index
expect(response).to be_success
end
end
end
responseはブラウザに返すべきアプリケーションの全データを保持しているオブジェクトです。
be_successはレスポンスステータスが成功(200)か、それ以外かをチェックするマッチャです。
特定のHTTPレスポンスコードを確認したいときはhave_http_statusが使えます。
require 'rails_helper'
RSpec.describe HomeController, type: :controller do
de
describe "#index" do
it "responds a 200 response" do
get :index
expect(response).to have_http_status "200"
end
end
end
#認証が必要なコントローラスペック
projectsコントローラのスペックを書いていきます。
このコントローラは、ログイン中のユーザーのみ自分に紐づいたプロジェクトを操作できるという、よくあるCRUDの構造になっています。
$ rails g rspec:controller project
##テスト前の準備
先ほどと同じく、まずは成功のレスポンスが返るかテストしますが、認証が必要なコントローラのアクションは事前の準備が必要です。
準備は大きく分けて2つ、
1.Deviseのヘルパーモジュールの読み込み
2.ログイン用のヘルパーメソッドの定義
です。順を追って説明します。
###Deviseのヘルパーモジュールの読み込み
Deviseは認証が必要なコントローラのアクションに対して、ユーザーのログイン状態をシミュレートするヘルパーを提供し、テスト実行時はこのヘルパーを使用しています。ですが、RSpecはデフォルトの状態だとこのヘルパーを読み込まないので、使えるように設定を追加します。
#この1行を追加します
config.include Devise::Test::ControllerHelpers, type: :controller
この設定で、コントローラスペックでDeviseのヘルパーモジュールが使えるようになります。
###ログイン用のヘルパーメソッドの定義
ユーザーがログインしていない状態でリクエストを送ると、ログインページにリダイレクト(302)が返るので、テストのセットアップとしてログインしておく必要があります。
スペック内でログイン処理を記述しても動作はしますが、ログイン処理は頻繁に行うので、今のうちにヘルパーを作っておくのがマストでしょう。
#各々のアプリに合わせたログイン処理
def sign_in(user)
cookies[:auth_token] = user.auth_token
end
##テスト
Projectsコントローラはログインユーザーとゲストユーザーで処理結果が異なるため、複数のテストシナリオを用意します。
require 'rails_helper'
RSpec.describe ProjectsController, type: :controller do
de
describe "#index" do
context "guest" do
it "returns a 302 response" do
get :index
expect(response).to have_http_status "302"
end
it "redirects to the sign_in page" do
get :index
expect(response).to redirect_to "users/sign_in"
end
end
context "logged_in" do
before do
@user = FactoryBot.create(:user)
end
it "responds successfully" do
sign_in @user
get :index
expect(response).to be_success
end
it "responds a 200 response" do
sign_in @user
get :index
expect(response).to have_http_status "200"
end
end
end
end
#ユーザーの入力をテスト
createアクションを例にPOST, PATCH, DESTROYリクエストもテストしていきます。
入力のエラーもテストも忘れないようにしましょう。
describe "#create" do
context "guest" do
it "returns a 302 response" do
project_params = FactoryBot.attributes_for(:project)
post :create, params: { project: project_params }
expect(response).to have_http_status "302"
end
it "redirects to the sign_in page" do
project_params = FactoryBot.attributes_for(:project)
post :create, params: { project: project_params }
expect(response).to redirect_to "/users/sign_in"
end
end
context "logged_in" do
before do
@user = FactoryBot.create(:user)
end
context "vaild attributes" do
it "adds a project" do
project_params = FactoryBot.attributes_for(:project)
sign_in(@user)
expect{
post :create, params: { project: project_params }
}.to change(@user.projects, :count).by(1)
end
end
context "invaild attributes" do
it "dose not add a project" do
project_params = FactoryBot.attributes_for(:project, :invalid)
sign_in(@user)
expect{
post :create, params: { project: project_params }
}.to_not change(@user.projects, :count)
end
end
end
end
#HTML以外の出力を扱う
CSVやJSONといったフォーマットでデータを返す処理のテストも見ていきます。
リクエストを送るコードで
format: :json
でフォーマットを指定し、
expect(response.content_type).to eq "application/json"
で帰ってきたデータのフォーマットを指定することでテストできます。