MAGAZINE
ルーターマガジン
FactoryBotでRailsのテスト用レコードを楽に作成する
こんにちは。アルバイトのハオです。今回はRailsのspecテストに役に立つfactory_bot(元factory_girl)について紹介したいと思います。FactoryBotで、テスト用のDBのレコードを便利に設定して作成することができますよ。
Railsアプリを用意
Railsアプリを新規作成し、モデル「User」と「Organization」を作成しましょう。
bundle exec rails generate model User name email organization_id
bundle exec rails generate model Organization name
bundle exec rake db:migrate
を忘れないでくださいね。
UserはOrganizationに所属するようにしたいので、has_many
とbelongs_to
を設定しましょう。
class Organization < ApplicationRecord has_many :users endapp/models/user.rb
class User < ApplicationRecord belongs_to :organization def self_intro "私の名前は#{name}です" end def self.filter_users_with_email self.where.not(email: [nil, ""]) end end
RspecとFactoryBotの導入
まずGemfileにgemを追加:
group :test do gem 'rspec-rails' gem "factory_bot_rails" end
bundle install
忘れないでくださいね。
さらにrspecをインストールしていきましょう。
bundle exec rails generate rspec:install
するとフォルダーspec
とファイルspec/rails_helper.rb
、spec/spec_helper.rb
を作ってくれます。
FactoryBot
FactoryBotは、テスト用のオブジェクトを生成するための、オブジェクトの「工場」をつくるような存在です。
フォルダーspecの下に、フォルダーfactoriesを作成し、その下に「工場」のファイルを書いてみましょう。
まずはモデルOrganizationの「工場」です。書いた通り、コラムnameが指定した値に定義されています。
spec/factories/organization.rbFactoryBot.define do factory :organization, class: Organization do name {"organization1"} end end
そしてモデルUserです。
spec/factories/user.rbFactoryBot.define do factory :user, class: User do sequence(:name) { |i| "test_#{i}_san"} trait :with_email do email {"test_trait@test.co.jp"} end association :organization end end
ここで、sequence, trait, associationなどの見慣れないキーワードが出ていますね。それぞれを紹介していきます。
sequenceでコラムnameを設定することで、オブジェクトを生成するごとに番号が+1、ユニークなnameを設定できます
traitに入ったコード、指定される限りに行います。
associationはhas_many、belongs_toなどのactiverecord関連のあるモデルの間しか効きません。このオブジェクト(ここはUserのオブジェクト)が生成されると、associationが指定したモデル(ここはOrganization)もオブジェクト一つを生成してくれます。関連も付きます(ここはuserのorganization_idも自動に設定されます)。
テストファイル
では、テストファイルを書きましょう。
spec/model/model_test.rb
require 'rails_helper' RSpec.describe "モデルテスト", type: :model do it "ユーザーを一つ作成(組織一つも自動に生成)" do FactoryBot.create(:user) user = User.first expect(user.organization).to be_present end it "一つの組織が複数のユーザーを持つ" do FactoryBot.create(:user) FactoryBot.create(:user, organization_id: 1) org = Organization.first expect(org.users.size).to eq 2 end it "メールを持っているユーザーだけをフィルター" do user = FactoryBot.create(:user) FactoryBot.create(:user, :with_email) users = User.filter_users_with_email expect(users.size).to eq 1 end it "ユーザーのメソッドself_intro" do FactoryBot.create(:user, name: "ルーター") user = User.first intro = user.self_intro expect(intro).to eq "私の名前はルーターです" end end
一番上のit "ユーザーを一つ作成(組織一つも自動に生成)"から見ていきましょう。FactoryBot.create(:user)
で、Userのオブジェクトを一つ、spec/factories/user.rbに書いた設定(ここは、nameがtest_1_sanに設定された)の通りに生成します。expect(user.organization).to be_present
で、生成したユーザーが所属する組織も生成されたかを確認します。
次のit "一つの組織が複数のユーザーを持つ"を見ていきましょう。FactoryBot.create(:user, organization_id: 1)
で、生成したユーザーオブジェクトの、spec/factories/user.rbにorganization_idの設定をオーバーライドし、1に設定します。
次のit "メールを持っているユーザーだけをフィルター"にいきましょう。このitは、モデルUserのクラスメソッドfilter_users_with_email
の効果を検証します。FactoryBot.create(:user, :with_email)
で、spec/factories/user.rbに書いてあるwith_emailというtraitを起こし、emailを持つユーザーひとつを作成します。filter_users_with_emailを実行し、取得するレコードはemailを持つユーザー一個のみのはずです。
最後のit "ユーザーのメソッドself_intro"は、モデルUserのメソッドself_intro
の効果を検証します。ここもFactoryBot.create(:user, name: "ルーター")
でnameを指定していますね。
最後に
いかがですか?FactoryBotでテストを書くと、テスト用レコードの作成は楽になりますよ。皆様もどんどん使ってみてください!
参考資料
- https://qiita.com/Ushinji/items/522ed01c9c14b680222c
- https://qiita.com/metheglin/items/47116ccbdb26aa00e034
- https://qiita.com/sabinuki/items/e64278ce775582f72634
CONTACT
お問い合わせ・ご依頼はこちらから