LoginSignup
6
3

More than 3 years have passed since last update.

RSpecのモデル単体テストにて外部キーを自動抽出する方法と注意点【初心者向け】

Posted at

開発環境

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. 任意の数字を入れた状態にする

spec/factories/address_order.rb
FactoryBot.define do
  factory :address_order do
# 省略
    item_id             { '1' }
    user_id             { '1' }
  end
end

2. Fakerでランダムな数字を生成する

spec/factories/address_order.rb
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を抽出する

spec/factories/address_order.rb
FactoryBot.define do
  factory :address_order do
# 省略
# 外部キーのカラムは消してしまう
#   item_id
#   user_id
  end
end
spec/models/address_order_spec.rb
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秒処理を待機させることで、負荷の軽減に成功している。

結果

テストが完了するまでに以前より少し時間がかかるようになったが、より実際の昨日に近いカタチで単体テストを記述することが出来た。

参考リンク

6
3
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
6
3