rspec-parameterizedにて、factory_botのtraitを動的に指定する

以前、factory_bottraitを使ったことがありました。
Rails + factory_botで、sub factoryやtrait・callbackを使って関連データを生成してみた - メモ的な思考的な

そんな中、 rspec-parameterized を使ってテストを書くときに、動的に trait を指定してデータを生成したくなりました。

そこで、実現できるかどうか試してみたときのメモを残します。

 
目次

 

環境

 
なお、今回使うfactoryはこんな感じです。

デフォルトでは name日本 が入りますが、 trait によりその値を変更できます。

FactoryBot.define do
  factory :area do
    name { '日本' }

    trait :tokyo do
      name { '東京都' }
    end

    trait :okinawa do
      name { '沖縄県' }
    end
  end
end

 

traitを使わない場合

trait を使わない場合は、 factory_botで定義されたデフォルト値が使われます。

context 'without trait' do
  let!(:static_area) { create(:area) }

  it 'static trait' do
    expect(static_area.name).to eq('日本')
  end
end

 

traitを静的に使ってデータを生成

trait を静的に使う場合は、 trait の値でデフォルト値が上書きされます。

RSpec.describe Area, type: :model do
  describe 'rspec-parameterized' do
    describe 'overwrite trait' do
      context 'static trait' do
        let!(:static_area) { create(:area, :tokyo) }

        it 'static trait' do
          expect(static_area.name).to eq('東京都')
        end
      end
    end
  end
end

 

rspec-parameterized + traitを動的に使ってデータを生成

続いて、 rspec-parameterized と組み合わせることで、パラメタライズドテストの中で動的に trait を指定する方法を試してみます。

実現するには

  • 事前に、 trait 用シンボルを入れる変数をletで定義しておく
  • rspec-parameterized にて、シンボルを入れる変数に、 trait として使えるシンボルを渡す
    • trait を使いたくない場合は、 nil を渡す

とすれば良さそうでした。

以下のテストコードもパスします。

context 'dynamic trait with rspec-parameterized' do
  let(:trait_symbol) { nil }
  let!(:dynamic_area) { create(:area, trait_symbol) }

  where(:trait_symbol, :result) do
    [
      [:tokyo, '東京都'],
      [:okinawa, '沖縄県'],
      [nil, '日本'],  # traitを使いたくない場合は nil を渡す
    ]
  end

  with_them do
    it 'dynamic trait' do
      expect(dynamic_area.name).to eq(result)
    end
  end
end

 

ソースコード

Githubに上げました。
https://github.com/thinkAmi-sandbox/rails_7_0_minimal_app

今回のプルリクはこちら。
https://github.com/thinkAmi-sandbox/rails_7_0_minimal_app/pull/15