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
お問い合わせ・ご依頼はこちらから