0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【RSpec】Railsチュートリアル第6版 第14章

Last updated at Posted at 2021-11-18

#はじめに
Railsチュートリアル第6版のテストをRSpecで書き直していく。

###目次

#Minitest

###Relationshipモデルのテスト

test/models/relationship_test.rb
require 'test_helper'

class RelationshipTest < ActiveSupport::TestCase

  def setup
    @relationship = Relationship.new(follower_id: users(:michael).id,
                                     followed_id: users(:archer).id)
  end

  test "should be valid" do
    assert @relationship.valid?
  end

  test "should require a follower_id" do
    @relationship.follower_id = nil
    assert_not @relationship.valid?
  end

  test "should require a followed_id" do
    @relationship.followed_id = nil
    assert_not @relationship.valid?
  end
end

###“following” 関連のメソッドのテスト

test/models/user_test.rb
require 'test_helper'

class UserTest < ActiveSupport::TestCase
  .
  .
  .
  test "should follow and unfollow a user" do
    michael  = users(:michael)
    archer   = users(:archer)
    assert_not michael.following?(archer)
    michael.follow(archer)
    assert michael.following?(archer)
    assert archer.followers.include?(michael)
    michael.unfollow(archer)
    assert_not michael.following?(archer)
  end

  test "feed should have the right posts" do
    michael = users(:michael)
    archer  = users(:archer)
    lana    = users(:lana)
    # フォローしているユーザーの投稿を確認
    lana.microposts.each do |post_following|
      assert michael.feed.include?(post_following)
    end
    # 自分自身の投稿を確認
    michael.microposts.each do |post_self|
      assert michael.feed.include?(post_self)
    end
    # フォローしていないユーザーの投稿を確認
    archer.microposts.each do |post_unfollowed|
      assert_not michael.feed.include?(post_unfollowed)
    end
  end
end

###フォロー/フォロワーページの認可のテスト

test/controllers/users_controller_test.rb
require 'test_helper'

class UsersControllerTest < ActionDispatch::IntegrationTest

  def setup
    @user = users(:michael)
    @other_user = users(:archer)
  end
  .
  .
  .
  test "should redirect following when not logged in" do
    get following_user_path(@user)
    assert_redirected_to login_url
  end

  test "should redirect followers when not logged in" do
    get followers_user_path(@user)
    assert_redirected_to login_url
  end
end

###following/followerをテストするためのリレーションシップ用fixture

test/fixtures/relationships.yml
one:
  follower: michael
  followed: lana

two:
  follower: michael
  followed: malory

three:
  follower: lana
  followed: michael

four:
  follower: archer
  followed: michael

###following/followerページのテスト

test/integration/following_test.rb
require 'test_helper'

class FollowingTest < ActionDispatch::IntegrationTest

  def setup
    @user  = users(:michael)
    @other = users(:archer)
    log_in_as(@user)
  end

  test "following page" do
    get following_user_path(@user)
    assert_not @user.following.empty?
    assert_match @user.following.count.to_s, response.body
    @user.following.each do |user|
      assert_select "a[href=?]", user_path(user)
    end
  end

  test "followers page" do
    get followers_user_path(@user)
    assert_not @user.followers.empty?
    assert_match @user.followers.count.to_s, response.body
    @user.followers.each do |user|
      assert_select "a[href=?]", user_path(user)
    end
  end

  test "should follow a user the standard way" do
    assert_difference '@user.following.count', 1 do
      post relationships_path, params: { followed_id: @other.id }
    end
  end

  test "should follow a user with Ajax" do
    assert_difference '@user.following.count', 1 do
      post relationships_path, xhr: true, params: { followed_id: @other.id }
    end
  end

  test "should unfollow a user the standard way" do
    @user.follow(@other)
    relationship = @user.active_relationships.find_by(followed_id: @other.id)
    assert_difference '@user.following.count', -1 do
      delete relationship_path(relationship)
    end
  end

  test "should unfollow a user with Ajax" do
    @user.follow(@other)
    relationship = @user.active_relationships.find_by(followed_id: @other.id)
    assert_difference '@user.following.count', -1 do
      delete relationship_path(relationship), xhr: true
    end
  end
end

###リレーションシップの基本的なアクセス制御に対するテスト

test/controllers/relationships_controller_test.rb
require 'test_helper'

class RelationshipsControllerTest < ActionDispatch::IntegrationTest

  test "create should require logged-in user" do
    assert_no_difference 'Relationship.count' do
      post relationships_path
    end
    assert_redirected_to login_url
  end

  test "destroy should require logged-in user" do
    assert_no_difference 'Relationship.count' do
      delete relationship_path(relationships(:one))
    end
    assert_redirected_to login_url
  end
end

#RSpec

###Relationshipモデルのテスト

spec/models/relationship_spec.rb
require 'rails_helper'

RSpec.describe Relationship, type: :model do
  
  let(:user) { FactoryBot.create(:user) }
  let(:other) { FactoryBot.create(:user) }
  let(:relationship) { Relationship.new(follower_id: user.id,followed_id: other.id) }

  it "should be valid" do
    expect(relationship).to be_valid
  end

  it "should require a follower_id" do
    relationship.follower_id = nil
    expect(relationship).to be_invalid
  end

  it "should require a followed_id" do
    relationship.followed_id = nil
    expect(relationship).to be_invalid
  end

end

letでrelationshipを作成しておく。

###“following” 関連のメソッドのテスト

spec/models/user_spec.rb
require 'rails_helper'

RSpec.describe User, type: :model do
  .
  .
  .
  describe "relationships" do

    let(:michael) { FactoryBot.create(:user) }
    let(:archer) { FactoryBot.create(:user) }
    let(:lana) { FactoryBot.create(:user) }

    before do
      michael.follow(lana)
    end

    it "should follow and unfollow a user" do
      expect(michael.following?(archer)).to be_falsy
      michael.follow(archer)
      expect(michael.following?(archer)).to be_truthy
      expect(archer.followers.include?(michael)).to be_truthy
      michael.unfollow(archer)
      expect(michael.following?(archer)).to be_falsy
    end

    it "feed should have the right posts" do  
      lana.microposts.each do |post_following|
        expect(michael.feed.include?(post_following)).to be_truthy
      end
      michael.microposts.each do |post_self|
        expect(michael.feed.include?(post_self)).to be_truthy
      end
      archer.microposts.each do |post_unfollowed|
        expect(michael.feed.include?(post_unfollowed)).to be_falsy
      end
    end

  end

end

relationshipのfixtureが無いので、before doでfollowしておく。

###フォロー/フォロワーページの認可のテスト

spec/requests/users_spec.rb
require 'rails_helper'

RSpec.describe "Users", type: :request do

  before do
  @user = FactoryBot.create(:user)
  @noadmin_user = FactoryBot.create(:user, :noadmin)
  end
  .
  .
  .
  it "should redirect following when not logged in" do
    get following_user_path(@user)
    expect(response).to redirect_to login_url
  end

  it "should redirect followers when not logged in" do
    get followers_user_path(@user)
    expect(response).to redirect_to login_url
  end

end

###following/followerページのテスト

spec/requests/followings_spec.rb
require 'rails_helper'

RSpec.describe "Followings", type: :request do
  
  let(:user) { FactoryBot.create(:user) }
  let(:other) { FactoryBot.create(:user) }
  let(:other2) { FactoryBot.create(:user) }
  let(:other3) { FactoryBot.create(:user) }

  before do
    log_in_as(user)
    user.follow(other2)
    user.follow(other3)
    other2.follow(user)
    other.follow(user)
  end

  it "following page" do
    get following_user_path(user)
    expect(user.following.empty?).to be_falsy
    assert_match user.following.count.to_s, response.body
    user.following.each do |user|
      assert_select "a[href=?]", user_path(user)
    end
  end

  it "followers page" do
    get followers_user_path(user)
    expect(user.followers.empty?).to be_falsy
    assert_match user.followers.count.to_s, response.body
    user.followers.each do |user|
      assert_select "a[href=?]", user_path(user)
    end
  end

  it "should follow a user the standard way" do
    expect{
      post relationships_path, params: { followed_id: other.id }
    }.to change(user.following, :count).by(1)
  end

  it "should follow a user with Ajax" do
    expect{
      post relationships_path, xhr: true, params: { followed_id: other.id }
    }.to change(user.following, :count).by(1)
  end

  it "should unfollow a user the standard way" do
    user.follow(other)
    relationship = user.active_relationships.find_by(followed_id: other.id)
    expect{
      delete relationship_path(relationship)
    }.to change(user.following, :count).by(-1)
  end

  it "should unfollow a user with Ajax" do
    user.follow(other)
    relationship = user.active_relationships.find_by(followed_id: other.id)
    expect{
      delete relationship_path(relationship), xhr: true
    }.to change(user.following, :count).by(-1)
  end

end

こちらもrelationship fixtureの代わりに、before doでフォロー関係を作成しておく。

###リレーションシップの基本的なアクセス制御に対するテスト

spec/requests/relationships_spec.rb
require 'rails_helper'

RSpec.describe "Relationships", type: :request do

  let(:user) { FactoryBot.create(:user) }
  let(:other) { FactoryBot.create(:user) }
  let!(:relationship) {Relationship.create(follower_id: user.id,followed_id: other.id)}
  
  it "create should require logged-in user" do
    expect{
      post relationships_path
    }.to_not change(Relationship, :count)
    expect(response).to redirect_to login_path
  end

  it "destroy should require logged-in user" do
    expect{
      delete relationship_path(relationship)
    }.to_not change(Relationship, :count)
    expect(response).to redirect_to login_path
  end

end

*"destroy should require logged-in user"*において使用する、userがotherをフォローしているというrelationshipをlet!で作成しておく。この際、userのログインが求められないように、Relationship.createを使用する。

#おわりに
今回テストを記述するにあたって、チュートリアルのテスト内容を忠実に再現することを意識していたため、RSpecの強みや良さを活かしきれていない部分が多々あると思う。
より良い書き方があれば是非コメントしていただきたい。
また、演習のテストは無視したので、気が向けば追加するつもりだ。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?