Techioz Blog

Rspec で Rails の移行をテストするときにインデックスを同時に削除する

概要

postgresデータベースのRails ActiveRecordを使用した新しい移行をテストするためのRspecテストを作成しています。移行ファイルは同時にインデックスを追加するため、私の移行には以下が含まれます。

disable_ddl_transaction!

add_index :table_name, [:column_1, :column_2], algorithm: :concurrently

移行の実行やロールバックに問題はありません。しかし、仕様ファイルを作成しているときに、インデックスの削除を含む以前の移行に戻す必要があり、次のエラーが発生します。

ActiveRecord::StatementInvalid:
       PG::InFailedSqlTransaction: ERROR:  current transaction is aborted, commands ignored until end of transaction block
       : SELECT pg_advisory_unlock(7815322980726126075)
     # ./spec/migrations/<FILE_NAME>.rb:17:in `block (3 levels) in <top (required)>'
     # ------------------
     # --- Caused by: ---
     # PG::ActiveSqlTransaction:
     #   ERROR:  DROP INDEX CONCURRENTLY cannot run inside a transaction block

開発段階では移行をロールバックできるのに、テスト環境でこの postgres エラーが発生する理由を理解しようとしています。

編集:これは、仕様ファイル内の目的の移行にロールバックする方法です。これがエラーを生成するものです。

before :each do
  ActiveRecord::MigrationContext.new(migration_paths).migrate(previous_version)
  ConferenceLink.reset_column_information
end

解決策

Rails-rspec にはデフォルト設定があり、各サンプルを独自のデータベース トランザクションで実行します。通常、サンプルの後にロールバックされ、次のサンプルで再びデータベースがクリーンになるようにします。

rspec-rails でこれらのトランザクションをグローバルに無効にすることができます。

RSpec.configure do |c|
  c.use_transactional_examples = false
end

ただし、各テストで実行している変更が他のテストの既存のデータベースに影響を与えないことを手動で確認する必要があります。 after ブロックでクリーンアップを実行するか、データベース クリーナー gem のようなものを使用します。

詳細と例についてはドキュメントを参照してください。