🎉

ActiveRecord::RecordNotUnique: Mysql2::Error: Duplicate entry エラーへの対処法

2023/08/03に公開

こんにちは、皆さん。最近、テストを実行しているときに面倒なエラーに遭遇しました。その名も 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