はじめに
Railsでテストコードを記述していたところ、必要事項を全て埋めても、外部参照したカラムの記述に関するエラーが出たので、FactoryBotでの外部参照キーの記述方法についてまとめました。
前提条件
下記のER図のようなUserモデルとArticleモデルにおいて、Articleモデルのuser_idが外部参照している場合を考えます。また、下記のようにUserのFactoryBotは定義済みとします。
# UserのFactoryBot
FactoryBot.define do
factory :user do
nickname {Faker::Name.name}
email {Faker::Internet.email}
password {Faker::Internet.password}
password_confirmation {password}
last_name {"投稿"}
first_name {"太郎"}
end
end
実行するテストコード
# Articleで実行するテストコード
require 'rails_helper'
describe Article do
before do
@article = FactoryBot.build(:article)
end
describe '記事新規投稿' do
context '新規投稿がうまくいく時' do
it '必要事項が全て存在すれば登録できる' do
expect(@article).to be_valid
end
end
context '新規投稿がうまくいかない時' do
it 'titleが空だと登録できない' do
@article.title = ""
@article.valid?
expect(@article.errors.full_messages).to include("Title can't be blank")
end
end
end
end
上記のように、Articleモデルの単体テスト実行の場合を考えます。今回は、簡単のために、正常系として必要事項が全て記述されたとき、異常系としてtitleカラムが空の場合のみを考えます。
エラーになったコード
# ArticleのFactoryBot
FactoryBot.define do
factory :article do
title {"あいうえお"}
prefecture_id {Faker::Number.within(range: 1..10)}
distance {Faker::Number.within(range: 10..500)}
content {"あいうえおかきくけこ"}
user_id {1}
end
end
最初は、上記のarticle.rbでArticleのFactoryBotを定義し、article_spec.rbのテストを実行しましたが、it '必要事項が全て存在すれば登録できる'の部分で'User must exist'のエラーが生じました。これにより、article_rbのuser_id {1} という記述だけでは、外部参照出来ていないことがわかります。
解決策1
# ArticleのFactoryBot
FactoryBot.define do
factory :article do
title {"あいうえお"}
prefecture_id {Faker::Number.within(range: 2..48)}
distance {Faker::Number.within(range: 10..500)}
content {"あいうえおかきくけこ"}
user {FactoryBot.create(:user)}
end
end
user_id {1} としていた部分をUserのFactoryBotで生成したインスタンスに変更しました。これにより、articlesテーブルで外部参照可能になり、無事article_spec.rbのテストコードが正しく実行されました。
解決策2
# ArticleのFactoryBot
FactoryBot.define do
factory :article do
title {"あいうえお"}
prefecture_id {Faker::Number.within(range: 2..48)}
distance {Faker::Number.within(range: 10..500)}
content {"あいうえおかきくけこ"}
association :user
end
end
次に、user_id {1} としていた部分をassociation :userという記述に変更しました。この記述でも、article_spec.rbのテストコードが正しく実行されました。
まとめ
FactoryBotで外部参照キーを記述する際は、user_id {1} などのように直接数字を記述するだけでは正しく外部参照できず、解決策①②のような記述が必要なことを学びました。