ヨージとプログラミング

プログラミング勉強の記録

【Rails】RSpecテストでActiveRecord::RecordInvalid:Validation failed: Email has already been taken エラー

環境

テスト後にロールバックしていない

該当のRSpec

require 'rails_helper'

describe 'レコード管理機能', type: :system do
  describe '一覧表示機能' do
    before do
      user_a = FactoryBot.create(:user, name: 'ユーザーA', email:'a@example.com')
      FactoryBot.create(:record, weight: 74.2, user: user_a)
    end
               〜 中略 〜
  end
end

テストの実行前にbefore doでuser_aを作成しています。
このテストを実行し、1回目は上手くいきましたが、まったく同じままもう一度テストするとエラーが出てしまいました。

# 同じテストの2回目で
$ docker-compose run web rspec
=>  ActiveRecord::RecordInvalid:
       Validation failed: Email has already been taken

Validation failed: Email has already been takenというエラー文そのままです。つまり、メールアドレスがすでに登録されててバリデーションエラーになっとるよということです。
ということは、1回目のテスト実行の時に作成したユーザーデータが残ってしまっているということになります。

rails_helper.rbを確認しよう

エラー文をそのままググると、「database_cleanerっていうgemを入れよう!」という解決策が一番に目につきますが、それよりもまず確認してほしいのは、RSpecをインストールした際に自動生成しているrails_helper.rbです。

RSpec.configure do |config|
  config.use_transactional_fixtures = true
  # ↑この一文が抜けていた
           〜 中略 〜
end

このconfig.use_transactional_fixtures = trueという1文がテストの終わりにdbをロールバックするものになります。あぁ、これが抜けてたのかー、書き足せば大丈夫だな!っと思いきや

テスト環境のDBをリセットしよう

ロールバックという操作はあくまで、一連のトランザクションの取り消しでしかありませんから、すでに登録されているデータまでをクリアしてくれる訳ではありません。 なので途中からconfig.use_transactional_fixtures = trueを書き足したとて

# rails_helper.rb修正後
$ docker-compose run web rspec
=>  ActiveRecord::RecordInvalid:
       Validation failed: Email has already been taken

バリデーションエラーはそのまま残ることになります。 なので一旦、DBのリセットを行いました。

$ docker-compose run web bundle exec rake db:migrate:reset RAILS_ENV=test

=> Starting weinance_chrome_1 ... done
Starting weinance_db_1     ... done
Dropped database 'app_name_test'
Created database 'app_name_test'
== 20190818090640 CreateRecords: migrating ====================================
-- create_table(:records)

              (以下略)

RAILS_ENV=testを忘れないでください。
そして再度チャレンジ

# 1回目
$ docker-compose run web rspec
=> Starting weinance_db_1 ... done
Starting weinance_chrome_1 ... done
         〜 中略 〜
Finished in 4.89 seconds (files took 8.88 seconds to load)
1 example, 0 failures

# 2回目
$ docker-compose run web rspec
=> Starting weinance_db_1     ... done
Starting weinance_chrome_1 ... done
         〜 中略 〜
Finished in 4.26 seconds (files took 7.33 seconds to load)
1 example, 0 failures

2回目も問題なくテストが通りました。