初めに
「書いて、慣れろ!」をしてると、前提知識の理解が浅いことで苦しみます。
焦らずに、知識を定着させましょう。ということで、FactoryBotのbuildとcreateについて理解できたので書きました。
問題
メールアドレスのバリデーション
validates :email, uniqueness: { case_sensitive: false }
FactoryBotでテストデータを生成
email { "info@example.com" }
テストデータで生成した小文字のメールアドレスと大文字のメールアドレス { build(:admin_user, email: 'INFO@example.com') }
が重複するケースを作る
RSpec.describe AdminUser, type: :model do
let(:admin_user) {build(:admin_user)}
describe "バリデーションの検証" do
context "メールアドレスが大文字と小文字に関わらず、重複した場合" do
let(:admin_user) { build(:admin_user, email: 'INFO@example.com') }
it "大文字のメールアドレスで登録すると、無効であること" do
admin_user_with_uppercase_email = build(:admin_user, email:'INFO@EXAMPLE.COM')
expect(admin_user_with_uppercase_email).to_not be_valid
end
end
end
end
Dockerコンテナで以下コマンドを実行
rspec spec/models/admin_user_spec.rb
バリデーションテストが失敗
Failure/Error: expect(admin_user).to_not be_valid
expected #<AdminUser id: nil, name: "AdminUser", email: "info@example.com", created_at: nil, updated_at: nil> not to be valid
解決方法
createメソッドでテスト実行前に info@example.com
をデータベースに保存する
context "メールアドレスが大文字と小文字に関わらず、重複した場合" do
before do
create(:admin_user, email: 'info@example.com')
end
it "大文字のメールアドレスで登録すると、無効であること" do
admin_user_with_uppercase_email = build(:admin_user, email: 'INFO@EXAMPLE.COM')
expect(admin_user_with_uppercase_email).to_not be_valid
end
end
原因
バリデーションルールの正確な理解
一意性の検証において、データを事前にデータベースに保存する必要性の認識が不足していました。小文字メールアドレスをFactoryBotで生成するだけで十分だと考えていました。
buildメソッドの挙動
オブジェクトをメモリ上にだけ生成し、データベースには保存しません。バリデーションのテストやアソシエーションの設定確認など、データベースに保存する必要がない場合に便利です。
終わりに
バリデーションルールの理解から順を追ってテストを実施することを学べました。