yamotonalds's blog

Webアプリケーション開発における技術メモが中心です。たまにWebサービス、興味を持ったデバイス、自作PCに関する話題もあるかも。Amazon好きなのでAmazon.co.jpアソシエイト使ってます。

rspec-rails3.0でのViewテストの書き方

rspec-rails3.0でのViewテストの書き方のメモ。

まずは公式に目を通しとくべき。

Upgrade - RSpec Rails - RSpec - Relish

view spec - View specs - RSpec Rails - RSpec - Relish

重なる内容もあるけど個人的に気になった点を以下に記述する。

Capybaraのmatchersを使う

have_tagは無くなったようなのでCapybaraをインストールしてそのmatchersを使う。

Module: Capybara::Node::Matchers — Documentation for jnicklas/capybara (master)

spec_helper.rbに以下の行を追加。

require 'capybara/rspec'

テストコードは以下のような感じになる。

describe "layouts/_navbar.html.haml" do
  subject do
    render partial: "layouts/navbar"
    rendered
  end

  describe "session info" do
    context "user not signed in" do
      it { should have_text I18n.t('layouts.navbar.sign_in') }
    end
  end
end
have_cssではオプションのキーを指定する

have_css(have_xpath, have_selector)のオプションには以下のようにtext:等のキーを付ける。

it { should have_css(".username", text: "アリス さん") }

付けなくてもテストは動くが、表示されるメッセージに違いがある。

# text: を付けた場合
should have css ".username" with text "アリス さん"

# text: を付けずに文字列のみを渡した場合
should have css ".username"
Library not loaded

発生条件まで追っていないが、自分の環境ではCapybaraをインストールするとrails起動時に以下のエラーが発生するようになった。

/Users/yamotonalds/Work/project_dir/vendor/bundle/ruby/1.9.1/gems/activesupport-3.2.13/lib/active_support/dependencies.rb:251:in `require': dlopen(/Users/yamotonalds/Work/project_dir/vendor/bundle/ruby/1.9.1/gems/nokogiri-1.6.0/lib/nokogiri/nokogiri.bundle, 9): Library not loaded: /Users/yamotonalds/.rvm/rubies/ruby-1.9.3-p327/lib/libruby.1.9.1.dylib
  Referenced from: /Users/yamotonalds/Work/project_dir/vendor/bundle/ruby/1.9.1/gems/nokogiri-1.6.0/lib/nokogiri/nokogiri.bundle
  Reason: image not found - /Users/yamotonalds/Work/project_dir/vendor/bundle/ruby/1.9.1/gems/nokogiri-1.6.0/lib/nokogiri/nokogiri.bundle (LoadError)

nokogiriを1.6.0から1.6.1にバージョンアップするとエラーは発生しなくなった。

bundle update nokogiri

Deviseを使っている場合

ReadmeにRSpecについての記述がある。

plataformatec/devise · GitHub

spec/support/devise.rbを作成して以下を記述する。

RSpec.configure do |config|
  config.include Devise::TestHelpers, type: :controller
  config.include Devise::TestHelpers, type: :view
end

これで以下のようにsign_in等が使える。

before do
  sign_in FactoryGirl.create(:user)
end

view.stub(:current_user, stub_model(User))とする方法もあるようだが、user_signed_in?等の他のメソッドもあるためUserクラスが使えるなら上記の方法で良いと思う。

helperのstub

before do
  view.stub(:admin?).and_return(true)
end

stub_modelとmock_modelの使い分け

大体以下のような感じだと思う。

stub_model

呼び出すごとに固有のid(正確にはto_param)を持ったインスタンスを作成する。指定するクラスは実在しなければならない。

つまり、実際にDBにデータを保存せずに永続化されたオブジェクトのdoubleを作るメソッド。

stub_model(Widget).as_new_record

とすることで永続化していないオブジェクトのdoubleも作れる。

mock_model

基本的にはstub_modelと同じで、ActiveModelのメソッドがstub化されたdoubleを作るメソッド。指定するクラスはActiveModel::Namingを継承している必要がある。

stub_modelとの大きな違いは実在しないクラスでも文字列で渡せばOKなところ。自動的にActiveModel::Namingを継承したクラスを作ってくれる。
分業しててViewのテストを作る時にまだ必要なクラスが作成されていない場合等に使える。

注意: Ruby 1.9.3では"Hoge::Foo"のようにモジュール内のクラスを指定するとNameErrorが発生する。Ruby 2.1.0では修正されていた。