Rails FactoryBot入門:RSpecで使うテストデータの作り方まとめ

スポンサーリンク

Rails FactoryBot入門:RSpecで使うテストデータの作り方まとめ

RSpec でテストを書くとき、テストデータを都度 User.create(name: "...") で作るのは手間がかかります。FactoryBot を使うと、モデルのデフォルトデータを一箇所に定義して create(:user) の一行で呼び出せます。


FactoryBot とは

テストデータのひな型(Factory)を定義するライブラリです。factory_bot_rails を使うと Rails / RSpec との連携が簡単にセットアップできます。


インストール・セットアップ

Gemfile:test グループに追加します。

group :test do
  gem 'factory_bot_rails'
end
bundle install

RSpec との連携設定

spec/support/factory_bot.rb を作成します。

RSpec.configure do |config|
  config.include FactoryBot::Syntax::Methods
end

spec/rails_helper.rb で読み込みます。

Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }

これで RSpec 内で create / build をそのまま呼び出せます。


Factory の定義

spec/factories/ ディレクトリに置きます。ファイル名はモデル名の複数形が慣例です。

# spec/factories/users.rb
FactoryBot.define do
  factory :user do
    name { "田中太郎" }
    email { "tanaka@example.com" }
    age { 25 }
  end
end

{ } ブロックで値を定義するのがポイントです。文字列を直接渡すと全テストで同じ値になり、一意制約があるカラムでエラーになります。

sequence でユニークな値を生成する

FactoryBot.define do
  factory :user do
    sequence(:name) { |n| "ユーザー#{n}" }
    sequence(:email) { |n| "user#{n}@example.com" }
    age { 25 }
  end
end

sequence を使うと呼び出すたびに n がインクリメントされ、一意な値を生成できます。


create / build / build_stubbed の使い分け

メソッド DB保存 用途
create(:user) する 標準的な利用。DB 経由のロジックが必要なとき
build(:user) しない バリデーションや属性の確認だけするとき
build_stubbed(:user) しない DB に触れずに高速に動かしたいとき
user = create(:user)       # DB に保存される
user = build(:user)        # 保存されない(new した状態)
user = build_stubbed(:user) # 保存されない + id が擬似的に設定される

テストが DB に依存しなくてよい場合は buildbuild_stubbed を使うとテストが速くなります。


RSpec での利用例

モデルスペック

# spec/models/user_spec.rb
RSpec.describe User, type: :model do
  describe 'バリデーション' do
    context '正常なデータのとき' do
      it '有効であること' do
        user = build(:user)
        expect(user).to be_valid
      end
    end

    context 'name が空のとき' do
      it '無効であること' do
        user = build(:user, name: '')
        expect(user).not_to be_valid
      end
    end
  end
end

属性を上書きするときは build(:user, name: '上書き値') のように引数で渡します。

リクエストスペック(コントローラー)

# spec/requests/users_spec.rb
RSpec.describe 'Users', type: :request do
  describe 'GET /users/:id' do
    let(:user) { create(:user) }

    it '200 を返すこと' do
      get user_path(user)
      expect(response).to have_http_status(:ok)
    end
  end

  describe 'POST /users' do
    context '正常なパラメーターのとき' do
      it 'ユーザーが作成されること' do
        expect {
          post users_path, params: { user: attributes_for(:user) }
        }.to change(User, :count).by(1)
      end
    end
  end
end

attributes_for(:user) を使うと Factory に定義した属性をハッシュで取得できます。フォームのパラメーターとして渡すときに便利です。


trait でバリエーションを定義する

管理者ユーザーや停止ユーザーなど、状態の違うデータを作りたいときは trait を使います。

FactoryBot.define do
  factory :user do
    sequence(:name) { |n| "ユーザー#{n}" }
    sequence(:email) { |n| "user#{n}@example.com" }
    age { 25 }
    role { :general }

    trait :admin do
      role { :admin }
    end

    trait :suspended do
      suspended_at { Time.current }
    end
  end
end

呼び出し方:

create(:user)             # 通常ユーザー
create(:user, :admin)     # 管理者ユーザー
create(:user, :suspended) # 停止ユーザー
create(:user, :admin, :suspended) # trait は複数組み合わせ可能

RSpec の context と組み合わせると読みやすくなります。

context '管理者ユーザーのとき' do
  let(:user) { create(:user, :admin) }

  it '管理画面にアクセスできること' do
    # ...
  end
end

association で関連モデルを作る

PostUser に属している場合、Factory に association を定義すると関連モデルを自動生成できます。

# spec/factories/posts.rb
FactoryBot.define do
  factory :post do
    title { "サンプル投稿" }
    body  { "本文テキスト" }
    association :user
  end
end
post = create(:post)
post.user # => 自動生成された User が入っている

既存のユーザーに紐付けたいときは属性で渡します。

user = create(:user)
post = create(:post, user: user)

まとめ

操作 書き方
Factory 定義 spec/factories/モデル名の複数形.rb
DB に保存して作成 create(:user)
DB に保存せず作成 build(:user)
属性を上書き create(:user, name: '別名')
trait 指定 create(:user, :admin)
ハッシュで取得 attributes_for(:user)
関連モデルを定義 association :user
ユニーク値を生成 sequence(:email) { |n| "user#{n}@example.com" }
  • sequence を使わないと一意制約エラーになりやすい
  • DB が不要なテストでは build / build_stubbed を使うとテストが速くなる
  • trait で状態のバリエーションを定義しておくと context と相性がよい

RSpec の基本については「RSpec入門:インストールからモデルスペックの書き方まで」も参照してください。