DiffDaily

Deep & Concise - OSS変更の定点観測

[Rails] テスト環境のENV汚染を徹底的にクリーンアップ

rails/rails

Context

Railsのテストスイートにおいて、ENV環境変数の変更が適切にクリーンアップされず、テスト間で状態が漏洩する問題が継続的に発生していました。この問題は#56563で報告され、特定のテスト実行順序で失敗が発生する原因となっていました。本PRは、この問題を根本的に解決するため、ENV変数の適切な管理とクリーンアップ処理を導入します。

Technical Detail

Rakeタスクでの ENV.delete パターンの導入

従来、Rakeタスクは ENV["FROM"] を直接参照していましたが、これがテスト後に環境変数を汚染していました。

変更前:

to_load = ENV["FROM"].blank? ? :all : ENV["FROM"].split(",").map(&:strip)

変更後:

from = ENV.delete("FROM")
to_load = from.blank? ? :all : from.split(",").map(&:strip)

ENV.delete を使用することで、値を取得すると同時に環境変数を削除し、後続のテストへの影響を防ぎます。

with_rails_env ヘルパーによるスコープ管理

複数のテストファイルで ENV["RAILS_ENV"] の直接代入が、with_rails_env ヘルパーを使ったスコープ管理に置き換えられました。

AssetDebuggingTestの改善:

test "assets are concatenated when debug is off and compile is off either if debug_assets param is provided" do
  with_rails_env("production") do
    rails "assets:precompile", "--trace"
    app "production"
    class ::PostsController < ActionController::Base ; end

    get("/posts?debug_assets=true", {}, "HTTPS" => "on")
    assert_match(/<script src="\/assets\/application-([0-z]+)\.js"><\/script>/, last_response.body)
  end
end

このパターンにより、ブロック終了時に自動的に RAILS_ENV が元の状態に戻ります。ViewReloadingTestServerTest でも同様の改善が行われています。

restore_default_config による設定リセット

一部のテストでは、不要な build_app 呼び出しが restore_default_config に置き換えられました。

test "config.active_job.verbose_enqueue_logs defaults to true in development" do
  restore_default_config
  app "development"

  assert ActiveJob.verbose_enqueue_logs
end

restore_default_config は既存のアプリケーション設定を再利用しつつ、環境変数をクリーンな状態に戻すため、テストの実行速度向上にも貢献します。

teardownでのENV削除処理の改善

teardown_app メソッドで、RAILS_ENV の復元処理が改善されました。

変更前:

def teardown_app
  ENV["RAILS_ENV"] = @prev_rails_env if @prev_rails_env
  # ...
end

変更後:

def teardown_app
  if @prev_rails_env
    ENV["RAILS_ENV"] = @prev_rails_env
  else
    ENV.delete("RAILS_ENV")
  end
  # ...

以前の実装では @prev_rails_envnil の場合にENV変数が残留していましたが、明示的に delete することで確実にクリーンアップされます。

Generatorテストでの改善

ActionMailboxInstallGeneratorTest では、run_generator メソッドをオーバーライドして、with_database_configuration ブロック内で実行するように統一されました。

private
  def run_generator
    quietly { with_database_configuration { super } }
  end

これにより、各テストケースで個別に with_database_configuration を呼び出す必要がなくなり、コードの重複が削減されました。

Impact

この変更により、Railsのテストスイート全体で環境変数の漏洩が防止され、テスト実行順序に依存する不安定なテスト失敗が解消されます。特に、CI環境での並列実行時の信頼性が大幅に向上します。