Ruby on Rails3 rspecによるdeviseを使ったコントローラーのテスト

rspecによるdeviseを使ったコントローラーのテストに手こずったのでメモ。

[環境]
Windows8
Ruby 1.9.3(p125)
Ruby on Rails 3.2.9
devise 2.2.3
factory_girl_rails 1.4.0
rspec-rails 2.13.0


spec\supportにcontroller_macros.rbを追加し、下記のように記述する。

module ControllerMacros
  def login_admin
    @request.env["devise.mapping"] = Devise.mappings[:admin]
    sign_in FactoryGirl.create(:admin)
  end

  def login_user
    controller.stub(:authenticate_user!).and_return true
    @request.env["devise.mapping"] = Devise.mappings[:user]
    user = FactoryGirl.create(:user)
    sign_in user
  end
end

wikiには「before(:each) do」や「user.confirm!」の記述があったが、私の環境ではエラーになったので削除した。
また、コントローラでbefore_filter :authenticate_user!にしているとsign_inしているにも関わらずroot_pathにリダイレクトされてしまうので、controller_macrosにスタブを追加した。


spec\speck_helper.rbに下記を追加

RSpec.configure do |config|
  config.include Devise::TestHelpers, :type => :controller
  config.extend ControllerMacros, :type => :controller
  # 以下略


spec\contorollersのテストしたいコントローラーのファイルに下記を記述。
(ここではmy_controllerのテストと仮定して、ファイル名はmy_controller_spec.rbとする。)

# coding: utf-8
require_relative "../spec_helper"

describe MyController do
  describe "GET #index" do
    context "ログインしていないとき" do
      it "ログイン画面にリダイレクトすべき" do
        get :index
        expect(response).to redirect_to(new_user_session_path)
      end
    end

    context "ログインしているとき" do
      before do
        login_user
      end

      it "responds successfully with an HTTP 200 status code" do
        get :index
        expect(response).to be_success
        expect(response.code).to eq("200")
      end

      it "renders the index template" do
        get :index
        expect(response).to render_template("index")
      end
      
      after do
        sign_out :user
      end
    end
  end
end

参考:
How To: Controllers and Views tests with Rails 3 (and rspec) · plataformatec/devise Wiki · GitHub
deviseを使ったコントローラのテスト #Ruby #Rails #Rspec #devise - Qiita