LoginSignup
3
4

More than 3 years have passed since last update.

Rspec 架空モデルのアソシエーション

Last updated at Posted at 2020-06-28

投稿背景

架空モデルが関係する部分でテストを実装していたところ、架空モデルの定義でエラーが解決できずにいて手こずっていたが、なんとか解決できたので備忘録として投稿

実装する機能

・チャット機能
・通知機能←こいつが強敵でした

モデルのアソシエーション

touristとguide、2種類のユーザー間で通知機能を実装するためのアソシエーション。

chat_notice.rb
belongs_to :guide_visitor, class_name: 'Guide', foreign_key: 'visitor_id', optional: true
belongs_to :guide_visited, class_name: 'Guide', foreign_key: 'visited_id', optional: true
belongs_to :tourist_visitor, class_name: 'Tourist', foreign_key: 'visitor_id', optional: true
belongs_to :tourist_visited, class_name: 'Tourist', foreign_key: 'visited_id', optional: true
tourist.rb
has_many :tourist_active_notices, class_name: 'ChatNotice', foreign_key: 'visitor_id', dependent: :destroy
has_many :tourist_passive_notices, class_name: 'ChatNotice', foreign_key: 'visited_id', dependent: :destroy
guide.rb
has_many :guide_active_notices, class_name: 'ChatNotice', foreign_key: 'visitor_id', dependent: :destroy
has_many :guide_passive_notices, class_name: 'ChatNotice', foreign_key: 'visited_id', dependent: :destroy

factory

chat_notice.rb
FactoryBot.define do
    factory :chat_notice do
        association :chat
        association :guide_visitor
        association :guide_visited
        association :tourist_visitor
        association :tourist_visited
    end
end

実行したテスト

chat_notice.rb
require 'rails_helper'

RSpec.describe ChatNotice, type: :model do
    let(:chat) { create(:chat) }
    let(:room) { create(:room) }
    let(:guide_visitor) { create(:guide) }
    let(:guide_visited) { create(:guide) }
    let(:tourist_visitor) { create(:tourist) }
    let(:tourist_visited) { create(:tourist) }
    let!(:chat_notice) { build(:chat_notice, chat_id: chat.id, visited_id: tourist_visited.id, visitor_id: guide_visitor.id) }


    describe 'ChatNotice保存テスト' do
        context 'チャット通知が正しく保存される' do
            it '全て入力されているので保存' do
                expect(chat_notice).to be_valid
            end
        end
    end

    describe 'ChatNoticeアソシエーションのテスト' do
        context 'Tourist_visitorモデルとの関係' do
            it 'N:1となっている' do
                expect(ChatNotice.reflect_on_association(:tourist_visitor).macro).to eq :belongs_to
            end
        end
        context 'Tourist_visitedモデルとの関係' do
            it 'N:1となっている' do
                expect(ChatNotice.reflect_on_association(:tourist_visited).macro).to eq :belongs_to
            end
        end
        context 'Guide_visitorモデルとの関係' do
            it 'N:1となっている' do
                expect(ChatNotice.reflect_on_association(:guide_visitor).macro).to eq :belongs_to
            end
        end
        context 'Guide_visitedモデルとの関係' do
            it 'N:1となっている' do
                expect(ChatNotice.reflect_on_association(:guide_visited).macro).to eq :belongs_to
            end
        end
    end
end

 エラー内容

こんな感じでキーが見つからないよーっていうエラーが出る。

# KeyError:
     #   key not found: "guide_visitor"

guide_visitorはguideモデルを基に定義された架空のモデルだから、factoryにguideを定義していればテストは通ると思ってたけど、失敗。

 原因

factory の定義の中で association を定義するということはその同名の factory が存在すること前提になってるみたいで、guide_visitorをfactoryに定義してなかったからエラーが発生してた。

 解決方法 : factory:キーワード引数

factory の association 定義に対して、それが利用することになる association 先の factory の名前を別のものにしたい場合にはfactory:キーワード引数で指定してやる

FactoryBot.define do
    factory :chat_notice do
        association :chat
        association :guide_visitor, factory: :guide  #factory: :guideを追加
        association :guide_visited, factory: :guide  #factory: :guideを追加
        association :tourist_visitor, factory: :tourist  #factory: :touristを追加
        association :tourist_visited, factory: :tourist  #factory: :touristを追加
        checked { Faker::Boolean.boolean }
    end
end
3
4
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
3
4