Factory Botのデフォルト値をランダムにするか固定値にするか
Factory Botで定義した値をランダム値にするか固定値にするか悩んでいたが、willnet/rspec-style-guide: 可読性の高いテストコードを書くためのお作法集 の説明がわかりやすかったので、コード例を抜粋しつつ以下にまとめる
アカウントが有効化されているかどうかを表すactiveカラムがあったときに、factoryを固定値で定義するとこんなかんじ
FactoryBot.define do
factory :user do
name { 'willnet' }
active { true }
end
end
RSpec.describe User, type: :model do
describe '#send_message' do
let!(:sender) { create :user, name: 'maeshima' }
let!(:receiver) { create :user, name: 'kamiya' }
it 'メッセージが正しく送られること' do
expect { sender.send_message(receiver: receiver, body: 'hello!') }
.to change { Message.count }.by(1)
end
end
end
これだとUser#activeがtrueであることが隠蔽されてしまっている
また、activeがfalseのときの振る舞いを明示できない
改善例がこちら
FactoryBot.define do
factory :user do
sequence(:name) { |i| "test#{i}" }
active { [true, false].sample }
end
end
RSpec.describe User, type: :model do
describe '#send_message' do
let!(:sender) { create :user }
let!(:receiver) { create :user }
it 'メッセージが正しく送られること' do
expect { sender.send_message(receiver: receiver, body: 'hello!') }
.to change { Message.count }.by(1)
end
end
end
activeの値をランダムにしており、これだとテストがactiveの値に依存しないことを明示できる
もしUser#activeのいずれかの値に依存するロジックに書き換わったのだとしたら、ランダムであることで特定の条件下でテストが落ちて気づくことができる
大事なのは「テストに依存している値をすべてテスト中に明示している」ということなので、それが守られているのであればFactoryBotのデフォルト値を固定にしてもかまわない。
仮にほとんどのテストがactiveの値がtrueで事足りる場合でも、各letで active: true とするか activeなユーザーのtraitを作るのが良いかもしれない