RailsチュートリアルのテストをRspecで書いてみた[第14章]
はじめに
今回はRspecの学習の一環として、RailsチュートリアルのテストをRspecで書いていきます。
至らない点があるかもしれませんが、その際はコメントにてご指摘をお願いします。
各種バージョン
Ruby 2.7.0
Rails 6.0.3.3
Rspec 3.9
Capybara 3.33.0
Factory_bot_rails 6.1.0
第14章
リスト14.4: Relationshipモデルのバリデーションをテストする
spec/models/relationships_spec.rb require 'rails_helper' RSpec.describe Relationship, type: :model do describe "validation" do let(:user) { FactoryBot.create(:user) } let(:other_user) { FactoryBot.create(:user) } let(:relationship) { user.active_relationships.build(followed_id: other_user.id) } it "is valid with test data" do expect(relationship).to be_valid end describe "presence" do it "is invalid without follower_id" do relationship.follower_id = nil expect(relationship).to be_invalid end it "is invalid without followed_id" do relationship.followed_id = nil expect(relationship).to be_invalid end end end end
リスト14.9: Relationshipモデルのバリデーションをテストする
spec/models/user_spec.rb require 'rails_helper' RSpec.describe User, type: :model do ・・・ describe "follow and unfollow" do let(:user) { FactoryBot.create(:user) } let(:other_user) { FactoryBot.create(:user) } before { user.follow(other_user) } describe "follow" do it "succeeds" do expect(user.following?(other_user)).to be_truthy end end describe "unfollow" do it "succeeds" do user.unfollow(other_user) expect(user.following?(other_user)).to be_falsy end end end end
リスト14.13: followersに対するテスト
spec/models/user_spec.rb require 'rails_helper' RSpec.describe User, type: :model do ・・・ describe "follow and unfollow" do let(:user) { FactoryBot.create(:user) } let(:other_user) { FactoryBot.create(:user) } before { user.follow(other_user) } describe "follow" do it "succeeds" do expect(user.following?(other_user)).to be_truthy end # ここから describe "followers" do it "succeeds" do expect(other_user.followers.include?(user)).to be_truthy end end # ここまで end describe "unfollow" do it "succeeds" do user.unfollow(other_user) expect(user.following?(other_user)).to be_falsy end end end end
リスト14.24: フォロー/フォロワーページの認可をテストする
spec/models/users_request_spec.rb require 'rails_helper' RSpec.describe "Users", type: :request do ・・・ describe "before_action: :logged_in_user" do let(:user) { FactoryBot.create(:user) } ・・・ it 'redirects following when not logged in' do get following_user_path(user) expect(response).to redirect_to login_url end it 'redirects followers when not logged in' do get followers_user_path(user) expect(response).to redirect_to login_url end end end
リスト14.29: following/followerページのテスト
spec/system/followings_spec.rb require 'rails_helper' RSpec.describe "Followings", type: :system do let(:user) { FactoryBot.create(:user) } let(:other_users) { FactoryBot.create_list(:user, 20) } before do other_users[0..9].each do |other_user| user.active_relationships.create!(followed_id: other_user.id) user.passive_relationships.create!(follower_id: other_user.id) end login_as(user) end scenario "The number of following and followers is correct" do click_on "following" expect(user.following.count).to eq 10 user.following.each do |u| expect(page).to have_link u.name, href: user_path(u) end click_on "followers" expect(user.followers.count).to eq 10 user.followers.each do |u| expect(page).to have_link u.name, href: user_path(u) end end end
create_listメソッドを使用すると、第2引数で指定した数のインスタンスをまとめて生成してくれます。
FactoryBot.create_list(:user, 20) # =>20個のテストデータを作成してくれます
リスト14.31: リレーションシップの基本的なアクセス制御に対するテスト
spec/requests/relationships_request_spec.rb require 'rails_helper' RSpec.describe "Relationships", type: :request do describe "Relationships#create" do let(:post_request) { post relationships_path } context "when not logged in" do it "doesn't change Relationship's count" do expect { post_request }.to change(Relationship, :count).by(0) end it "redirects to login_url" do expect(post_request).to redirect_to login_url end end end describe "Relationships#destroy" do let(:user) { FactoryBot.create(:user) } let(:other_user) { FactoryBot.create(:user) } let(:delete_request) { delete relationship_path(other_user) } before { user.following << other_user } context "when not logged in" do it "doesn't change Relationship's count" do expect { delete_request }.to change(Relationship, :count).by(0) end it "redirects to login_url" do expect(delete_request).to redirect_to login_url end end end end
リスト14.40: [Follow] / [Unfollow]ボタンをテストする
spec/system/followings_spec.rb require 'rails_helper' RSpec.describe "Followings", type: :system do let(:user) { FactoryBot.create(:user) } let(:other_users) { FactoryBot.create_list(:user, 20) } before do other_users[0..9].each do |other_user| user.active_relationships.create!(followed_id: other_user.id) user.passive_relationships.create!(follower_id: other_user.id) end login_as(user) end ・・・ scenario "When user clicks on Unfollow, the number of following increases by -1" do visit user_path(other_users.first.id) expect do click_on "Unfollow" expect(page).not_to have_link "Unfollow" # Ajaxの処理待ちの為に入れています visit current_path end.to change(user.following, :count).by(-1) end scenario "When user clicks on Follow, the number of following increases by 1" do visit user_path(other_users.last.id) expect do click_on "Follow" expect(page).not_to have_link "Follow" # Ajaxの処理待ちの為に入れています visit current_path end.to change(user.following, :count).by(1) end end
リスト14.42: ステータスフィールドのテスト
ユーザのテストデータを作成した際、マイクロポストも一緒に作成されるようにFactoryBotの機能の一つコールバックを使用します。
spec/factories/users.rb FactoryBot.define do factory :user do name { "TestUser" } sequence(:email) { |n| "test#{n}@example.com" } password { "foobar" } password_confirmation { "foobar" } activated { true } activated_at { Time.zone.now } trait :admin do admin { true } end trait :no_activated do activated { false } activated_at { nil } end # 新しく追加しています。 trait :with_microposts do after(:create) { |user| create_list(:micropost, 5, user: user)} end end end
spec/models/user_spec.rb require 'rails_helper' RSpec.describe User, type: :model do ・・・ describe "def feed" do let(:user) { FactoryBot.create(:user, :with_microposts) } let(:other_user) { FactoryBot.create(:user, :with_microposts) } context "when user is following other_user" do before { user.active_relationships.create!(followed_id: other_user.id) } it "contains other user's microposts within the user's Micropost" do other_user.microposts.each do |post_following| expect(user.feed.include?(post_following)).to be_truthy end end it "contains the user's own microposts in the user's Micropost" do user.microposts.each do |post_self| expect(user.feed.include?(post_self)).to be_truthy end end end context "when user is not following other_user" do it "doesn't contain other user's microposts within the user's Micropost" do other_user.microposts.each do |post_unfollowed| expect(user.feed.include?(post_unfollowed)).to be_falsy end end end end end