【Rails6】RSpecによるレビュー機能の結合テストの実装


はじめに

サービスの品質を保つために必要不可欠なテストを実施しております。

今回はレビュー機能の結合テストを実装し、その実装内容を記事にしていきたいと思います。

前提

・レビュー機能は実装済み
・Review(レビュー)モデルの単体テストは実施済み

※完了されていない方や単体テストと並行してご覧になられたい方は、以下のReviewモデルの単体テストについての記事をご参考ください。

バージョン

rubyのバージョン ruby-2.6.5
Railsのバージョン Rails:6.0.0
rspec-rails 4.0.0

実施したテスト

レビュー画面

reviewsテーブルのカラムの紹介

xxx_create_reviews.rb
class CreateReviews < ActiveRecord::Migration[6.0]
  def change
    create_table :reviews do |t|
      t.string :content
      t.integer :score
      t.references :user,       foreign_key: true
      t.references :definition, foreign_key: true
      t.timestamps
    end
  end
end

モデル内のバリデーション

app/models/review.rb
class Review < ApplicationRecord
  belongs_to :user
  belongs_to :definition

  validates :user_id, presence: true
  validates :definition_id, presence: true
  validates :score, presence: true
  validates_uniqueness_of :definition_id, scope: :user_id
end

FactoryBotの内訳

spec/factories/reviews.rb
FactoryBot.define do
  factory :review do
    association :definition
    association :user
    content                       {Faker::Lorem.word}
    score                         {'3'}
  end
end

サポートモジュール

spec/support/review_up_support.rb
module ReviewUpSupport
  def review_up(review)
  # レビュー作成ページに遷移する
  visit new_definition_review_path(@definition)

  # レビューの存在の確認
  expect(page).to have_selector '#star1'
  expect(page).to have_selector '#star2'
  expect(page).to have_selector '#star3'
  expect(page).to have_selector '#star4'
  expect(page).to have_selector '#star5'

  # 星マークにカーソルを合わた場所でクリックする(今回は3段階)
  expect(find('#star3').hover.click)

  # レビューのコメントに情報を入力する
  fill_in 'review[content]', with: review.content

  # レビューのコメントを送信すると、Reviewモデルのカウントが1上がることを確認する
  expect{
    find('input[name="commit"]').click
  }.to change { Review.count }.by(1)
  end
end

テストコードの内容

spec/system/reviews_spec.rb
require 'rails_helper'

RSpec.describe "Reviews", type: :system, js: true do
  before do
    @definition = FactoryBot.create(:definition)
    @review = FactoryBot.create(:review)
  end
    describe '#create,#destroy' do
      context 'レビューができるとき' do
        it 'ユーザーが投稿に対してレビューができる' do
        # ログインする
        sign_in(@definition.user)

        #新規レビューを作成する
        review_up(@review)

        # # レビュー詳細ページに遷移する
        visit definition_reviews_path(@definition)

        # レビュー詳細ページにてレビューした投稿があることを確認する
        expect(page).to have_content(@review.score)
        expect(page).to have_content(@review.content)
        end
      end

      context 'レビューができないとき' do
        it 'ユーザーが投稿に対してレビューをすでにしており、レビューができない' do
         # ログインする
         sign_in(@definition.user)

         # レビュー作成ページに遷移する
         visit new_definition_review_path(@definition)

         #新規レビューを作成する
         review_up(@review)

         # レビュー作成ページに遷移する
         visit new_definition_review_path(@definition)

         # 星マークにカーソルを合わた場所でクリックする(今回は3段階)
         expect(find('#star3').hover.click)

         # レビューのコメントに情報を入力する
         fill_in 'review[content]', with: @review.content

         # レビューのコメントを送信すると、Reviewモデルのカウントが上がらないことを確認する
         expect{
          find('input[name="commit"]').click
        }.to change { Review.count }.by(0)

        # レビューページへ戻されることを確認する
         expect(current_path).to eq(definition_reviews_path(@definition))
        end
      end
   end
end

補足説明

#starについて

星マークを記述しているview内のidであり、今回は5つあります。
テストの関係上idを区別する必要があったため番付しています。

app/views/reviews/index.html.erb
# 〜省略〜
      <span class="fa fa-star-o" id="star1"></span>
      <span class="fa fa-star-o" id="star2"></span>
      <span class="fa fa-star-o" id="star3"></span>
      <span class="fa fa-star-o" id="star4"></span>
      <span class="fa fa-star-o" id="star5"></span>
# 〜省略〜

'#'を文頭につけることでidを指し示すことができます。

異常系のReview.countについて

モデル内にuniqunessのバリデーションをかけており、レビューは1回しかできない仕様にしています。

app/models/review.rb
validates_uniqueness_of :definition_id, scope: :user_id

したがって一度レビューし、再度レビューしてもレビューカウントは上がらず0のままを証明できれば、レビューができていないことが言えます。

以上です。