びぼろく!

すごいプログラマになるためのびぼうろく。ruby rails mysql swift AWS Linux

rspecでcontrollerをテストするときの基礎まとめ

everydayrailsrspecがものすごくrspecの勉強になる

まだ途中だけど、これは買ってよかった

Read Everyday Rails - RSpecによるRailsテスト入門 | Leanpub

すぐに忘れてしまうので、自分用にメモ

よく使うメソッドまとめ

メソッド 説明
assigns controllerのインスタンス変数の値を参照する
eq 値が等しいかどうか。配列の場合は順番も同じでないといけない
match_array 配列の要素が等しいかどうか。順番は関係ない
attributes_for 設定した属性値の値が返ってくる(factory girl)
change とにかくなにか変化したことを期待する
change().by(value) 評価前と評価後の差がvalueである
change().from(old).to(new) 評価前(from)から評価後(to)になっていること

各アクションで行うテスト(一部抜粋)

index , new

responseのページがindexかどうか確かめるだけのテスト

it "render template index" do
  get :index
  expect(response).to render_template :index
end
  • newの場合
    • :indexnewに変わるだけ

edit

it "assigns edit User" do
  test_user = create(:user)
  get :edit, id: test_user
  expect(assigns(:user)).to eq(test_user)
end
  • get :edit, id: test_user

上記のコードは、viewで下記のように指定したと同じようなこと。

<%= form_for(@user) do |f| %>
  <% f.submit %>
<% end %>
  • expect(assigns(:user)).to eq(test_user)

    • assigns(:user)でcontrollerのインスタンス変数の値を取得。そして、createしたユーザと値が一致しているか確かめる
  • さっきのindex,userと同じように、ページ表示だけを確かめた場合は下記のようになる。

it "assigns edit User" do
  test_user = create(:user)
  get :edit, id: test_user
  expect(response).to render_template :edit
end

create

DBに登録されたかどうかの確認

成功の場合
it "save success" do
  expect { 
    post :create, user: attributes_for(:user)
  }.to change(User, :count).by(1)
end
  • expectにブロックを渡す
    • 実行前と実行後で評価される
  • user: attributes_for(:user)
    • attributes_forでhash形式で送られるので、controllerの@userインスタンスに値が入る
  • change(User, :count).by(1)
    • createしたあとに、User.countをして、差分が1増えているか確認する。saveしたあとなら、DBにインサートされているから実行前と差分が1あるはず。
失敗を想定した場合
it "save success" do
  expect { 
    post :create, user: attributes_for(:user)
  }.not_to change(User, :count)
end

DBへ登録したあとのページ遷移のテスト

成功の場合
it "redirect to :index" do
   post :create, user: attributes_for(:user)
   expect(response).to redirect_to users_path(assigns([:users]))
end
  • users_path(assigns([:users]))
    • redirectした先がindexページであること。また、登録したユーザが取得できていることを確認する
失敗を想定した場合
it "redirect to :new" do
   post :create, user: attributes_for(:user, name: nil)
   expect(response).to render_template :new
end
  • attributes_for(:user, name: nil)
    • わざとvalidateエラーにかかるデータを作る

update

ページの表示確認

it "set valiable :user" do
  patch :update, id: test_user, user: attributes_for(:user)
  expect(assigns(:test_user)).to eq(test_user)
end

update時のデータの確認

成功の場合
it "change user" do
   patch :update, id: user, user: attributes_for(:user, name: "テスト")
   user.reload
   expect(user.name).to eq("テスト")
end

*user.reload * データベースからレコードを再取得

失敗を想定した場合
it "dose not change user" do
   patch :update, id: user, user: attributes_for(:user, name: "テスト", url: nil)
   user.reload
   expect(user.name).to eq("テスト")
end
  • user: attributes_for(:user, name: "テスト", url: nil)
    • validateエラーにかかるようにして、データが更新されないことを確認する

update後のページ遷移確認

成功の場合
it "redirect to index" do
  patch :update, id: user, user: attributes_for(:user)
  expect(response).to redirect_to users_path
end
失敗を想定した場合
it "redirect to index" do
  patch :update, id: user, user: attributes_for(:user, name: nil)
  expect(response).to render_template :edit
end

まとめ終わり!

ちょっとずつrspecの使いかたに慣れてきた

shared exampleとかヘルパーマクロのこともそのうちまとめて行きたし。