rspec-rails3.0でのControllerテストの書き方
Controllerテストの書き方のメモ。
通常のページ
require 'spec_helper'
describe HogesController do
describe "GET show" do
let(:request) { get :show, id: 1 }
subject do
request
end
it { should be_ok }
it { should render_template "show" }
describe "@hoge" do
subject do
request
assigns(:hoge)
end
it { should be_present }
end
end
describe "DELETE destroy" do
let(:request) { delete :destroy, id: 1 }
before do
@hoge = stub_model(Hoge, destroy: nil)
allow(Hoge).to receive(:find).and_return(@hoge)
end
subject do
request
end
it { should be_success }
it { should redirect_to hoges_path)
describe "@hoge" do
subject do
request
assigns(:hoge)
end
it { should be_present }
it "#destory called once" do
expect(@hoge).to receive(:destroy).once
subject
end
end
end
end
get
やpost
はResponse
オブジェクトを返すのでそれをテストする。
ロジックの呼び出しに関してはモックでテスト。
ステータスコードは、
its(:status) { should eq 200 }
# または
its(:status) { should eq Rack::Utils.status_code(:ok) }
でも確認できるが可読性やタイプ数を考えるとbe_*
で済むものは済ませたい。
使いそうなのは、
- be_ok # 200
- be_success # 200番台
- be_successful # 200番台
- be_redirect # 301, 302, 303, 307のどれか
- be_forbidden # 403
- be_not_found # 404
- be_missing # 404
あたりか。
アサインした変数と意図したテンプレートが使われたかはチェックするがそのレンダリング内容についてはViewのテストで行うのでここではテストしない。
@hoge
はFactoryGirl.create(:hoge)
でも良いのだがstub_model
の方がテストの実行時間が短くなるので積極的に利用する(そもそもコントローラのテストは本質的にはDBは不要)。
※2014-03-07 stubを使う部分のコードがmochaのものになっていたのでrspecのものに修正
mochaをインストールしていたせいかspec_helper.rb
でmochaを使う設定にしていないのにstubs
やreturns
を使っていても表面上はエラーにならなかった。
しかし、specファイルを指定して実行してもエラーにならないがall testだとエラーになる現象が発生するようになった(100%ではなくall testが通る場合もある)。調べるとあるspecファイルで使ったstubs
が他のspecファイルでも有効になっていた(そのためテストの実行順によってはall testが通った)。
Deviseを使う場合
spec/support/devise.rb
を以下の内容で作成。
RSpec.configure do |config|
config.include Devise::TestHelpers, type: :controller
end
これでsign_in
, sign_out
が使える。
また、DeviseController
を継承したコントローラのテストではリクエスト前に
@request.env["devise.mapping"] = Devise.mappings[:user]
が必要になる。
Ajaxを使う場合
Viewのlink_to
等でremote: true
とした場合、.js
がリクエストされるのでテストでは次のようにリクエストする。
delete :destroy, id: 1, format: :js
これで406 Not Acceptable
になるようならアクションのrespond_to
にformat.js
が書かれていないと思われる。
また、401
になる場合はログイン状態、403
になる場合はCanCan等承認周りを確認する。