🎉
ActiveRecord::RecordNotUnique: Mysql2::Error: Duplicate entry エラーへの対処法
こんにちは、皆さん。最近、テストを実行しているときに面倒なエラーに遭遇しました。その名も ActiveRecord::RecordNotUnique: Mysql2::Error: Duplicate entry
。このエラーに対する解決法を共有したいと思います。
1. エラーの原因
実際に遭遇したエラーの背後には、テストデータの作成時に発生するIDの競合が原因として上がってきました。具体的には、FactoryBotを使用してテストデータを作成する際に、id
を明示的に指定していました。
FactoryBot.define do
factory :sample_model do
sequence(:id) { |n| n }
name { "sample#{n}" }
end
end
これは、RDBMS(例えばMySQL)が通常自動的に採番するid
を上書きしてしまうため、複数のテストが同時に実行されるとIDの競合が発生します。
2. 解決策
このエラーを解決するための最も簡単な方法は、Factoryの定義からid
の指定を削除することです。
FactoryBot.define do
factory :sample_model do
name { "sample#{n}" }
end
end
3. テストデータベースのクリーンアップ
さらに、テストデータベースの状態をリセットすることで、テスト間の干渉を避けることができます。database_cleaner
gemを使用すると、テストの前後でデータベースの状態を簡単に管理できます。
# Gemfile
gem 'database_cleaner'
# spec/rails_helper.rb または spec_helper.rb
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.strategy = :transaction
end
config.before(:each, js: true) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
4. まとめ
今回のエラーは、FactoryBotでのデータ定義に潜んでいました。テストデータの作成時に不要な属性を明示的に指定しないこと、そしてdatabase_cleaner
を使用してテスト間でのデータベースの状態を綺麗に保つことが重要です。
テストはアプリケーションの品質を保証するためのもの。エラーと向き合いながら、より良いテスト環境を整えていきたいと思います。
Discussion