`actionpack`テストの`NotificationAssertions`ヘルパーへの移行
actionpack/test/controller/redirect_test.rb内のActiveSupport::Notifications関連テストが、NotificationAssertionsヘルパーを使うよう整理されました。手動でのサブスクライバー管理とensureブロックによるクリーンアップが不要になり、テストコードの意図がより明確になります。
背景
Railsのテストスイートでは、ActiveSupport::Notificationsのイベント発行を検証するために、サブスクライバーの手動登録・収集・解除というボイラープレートが繰り返し書かれていました。ActiveSupport::Testing::NotificationAssertionsモジュールは#53065および#54126でこの問題に対処するために追加され、capture_notificationsやassert_notificationといったヘルパーを提供しています。
#53819ではactionpackの一部テストが既にこのヘルパーへ移行されており、今回の#56956はその続きとしてredirect_test.rb内の残るテスト群を対象にしています。
移行対象となったのは、"unsafe_redirect.action_controller"イベントの発行を検証する5つのテストです。これらはwith_path_relative_redirect(:notify)ブロック内で通知イベントをキャプチャし、ペイロードの内容を詳細にアサートする構造を持っていました。
技術的な変更
capture_notificationsヘルパーを使うことで、サブスクライバーの手動管理が1行の呼び出しに集約されました。
変更前:
def test_redirect_to_path_relative_url_starting_with_an_at_with_notify
with_path_relative_redirect(:notify) do
events = []
subscriber = ActiveSupport::Notifications.subscribe("unsafe_redirect.action_controller") do |*args|
events << ActiveSupport::Notifications::Event.new(*args)
end
get :redirect_to_path_relative_url_starting_with_an_at
assert_response :redirect
# ...
ensure
ActiveSupport::Notifications.unsubscribe(subscriber) if subscriber
end
end
変更後:
def test_redirect_to_path_relative_url_starting_with_an_at_with_notify
with_path_relative_redirect(:notify) do
events = capture_notifications("unsafe_redirect.action_controller") do
get :redirect_to_path_relative_url_starting_with_an_at
end
assert_response :redirect
# ...
end
end
変更の内容は3点に集約されます。まず、ActiveSupport::Notifications.subscribeの呼び出しとEventオブジェクトへの変換がcapture_notificationsの1行に置き換えられました。次に、getによるリクエスト発行がヘルパーのブロック内に移動し、イベントキャプチャのスコープが明示されました。最後に、ensureブロックによるActiveSupport::Notifications.unsubscribeの呼び出しが不要になりました。capture_notificationsはブロック終了後に自動でサブスクライバーを解除するためです。
この変更はペイロードへのアサーション部分(event.payload[:message]やevent.payload[:stack_trace]の検証)には手を加えていません。capture_notificationsが返すevents配列に対して従来どおりevents.firstでイベントを取り出してアサートする構造を維持しており、既存の検証ロジックはそのまま保たれています。
設計判断
ペイロードの詳細なアサーションが必要なケースではassert_notificationではなくcapture_notificationsが選択されています。
NotificationAssertionsはassert_notificationとcapture_notificationsの2つの主要なAPIを持ちます。assert_notificationはペイロードのサブセットマッチングと単純な発行確認に向いており、capture_notificationsは取得したイベントオブジェクトに対して任意のアサーションを行いたい場合に適しています。今回のテストではstack_trace配列の内容検証など複合的なアサーションが必要なため、capture_notificationsでイベントを取得して手動でアサートするアプローチが採用されています。これは#54126がマッチしたNotificationを返すようassert_notificationを拡張した設計意図とも一致しています。
まとめ
本PRは機能変更を伴わない純粋なリファクタリングですが、ensureによるクリーンアップの省略とスコープの明示化によって、テストが「何を検証しているか」をより直接的に表現できるようになっています。NotificationAssertionsヘルパーの段階的な適用が進むことで、Railsのテストスイート全体のボイラープレートが体系的に削減されていく流れの一環です。