開発環境
system | version |
---|---|
macOS Catalina | 10.15.7 |
Ruby on Rails | 6.0.0 |
pry_rails | 4.0.0 |
Bundler | 2.1.4 |
rspec_rails | |
factory_bot_rails | |
faker |
自動抽出が何故必要か
モデル単体テストでは、如何に実際のデータ保存機能に近い検証が出来ているかが鍵となるからである。
さて、子モデルのインスタンスをFactoryBotで生成する際、親モデルのidを外部キーとして持たせる必要があり、これには何パターンかやり方が考えられる。
1. 任意の数字を入れた状態にする
FactoryBot.define do
factory :address_order do
# 省略
item_id { '1' }
user_id { '1' }
end
end
2. Fakerでランダムな数字を生成する
FactoryBot.define do
factory :address_order do
# 省略
item_id { Faker::Number.non_zero_digit }
user_id { Faker::Number.non_zero_digit }
end
end
3. 親モデルから紐づいているインスタンスのidを抽出する
FactoryBot.define do
factory :address_order do
# 省略
# 外部キーのカラムは消してしまう
# item_id
# user_id
end
end
require 'rails_helper'
RSpec.describe AddressOrder, type: :model do
before do
# 親モデルのインスタンスを生成する
@user = FactoryBot.create(:user)
@item = FactoryBot.create(:item)
# 親モデルのインスタンスからidを抽出する
@order = FactoryBot.build(:address_order, user_id: @user.id, item_id: @item.id)
sleep 0.1
end
# 省略
end
どのパターンでも問題なくテストを行うことが出来るが、厳密に言うと子モデルのインスタンスにおける外部キーは、親モデルの紐づいているインスタンスからマージされる存在であるため、パターン3で記述することが望ましい。
これによって、実際のデータ保存機能により近いテストを行うことが出来る。
注意点
beforeメソッド内にsleep 0.1
という記述があるが、この1文がなかった場合以下のようなエラーに遭遇した。
(一部省略)
このエラー原因や解消法に関しては、『RSpecのテスト中にMySQL client is not connected』 を参照した。
一言でいうと、インスタンス生成に過剰な負荷がかかってしまったことによって発生するエラーである。そのため、sleep 0.1
をbeforeメソッド内に記述することによってインスタンスを生成する度に0.1秒処理を待機させることで、負荷の軽減に成功している。
結果
テストが完了するまでに以前より少し時間がかかるようになったが、より実際の昨日に近いカタチで単体テストを記述することが出来た。