ルーティングヘルパーのmethod_missingをActionController::TestCaseに移動
ルーティングアサーション内の method_missing が ActionController::TestCase に移動されました。この変更により、コントローラーテストと統合テストでのURLヘルパーアクセスの責務分離が明確になります。
背景
従来、ActionDispatch::Assertions::RoutingAssertions モジュールに定義されていた method_missing は、コントローラーテスト専用の機能でした。このメソッドには「ROUTES TODO: These assertions should really work in an integration context」というコメントが付いていましたが、実際には統合テストでは別の仕組みでURLヘルパーにアクセスしています。
統合テストは integration_session 経由でルーティングヘルパーにアクセスする独自の実装を持っており、このTODOコメントは実態と合わなくなっていました。#49821 は、この不整合を解消するための変更です。
技術的な変更
method_missing の定義場所が ActionDispatch::Assertions::RoutingAssertions から ActionController::TestCase に移動されました。
変更前:
def method_missing(selector, ...)
if @controller && @routes&.named_routes&.route_defined?(selector)
@controller.public_send(selector, ...)
else
super
end
end
変更後:
def method_missing(selector, *args, &block)
if defined?(@controller) && @controller && defined?(@routes) && @routes && @routes.named_routes.route_defined?(selector)
@controller.public_send(selector, *args, &block)
else
super
end
end
ruby2_keywords(:method_missing)
変更後のコードでは、defined? による存在チェックが追加され、ruby2_keywords によるキーワード引数の適切な処理が保証されています。これにより、より堅牢なメソッド委譲が実現されました。
統合テストでは、ActionDispatch::Integration::Session が独自に URL_HELPERSモジュールをinclude しており、@integration_session に委譲する実装 を持っています。今回の移動により、コントローラーテストと統合テストのURLヘルパーアクセスが完全に分離されました。
設計判断
テストコンテキストごとに適切な場所に配置する方針 が採用されました。
PRの議論では、この method_missing がpublic APIとして外部に公開されている可能性が検討されましたが、実際には ActionController::TestCase のコンテキストでのみ使用されることが想定されています。統合テストには既に独自の実装があるため、ルーティングアサーションモジュールに置いておく必要はありませんでした。
テストケースも追加され、with_routing ブロック内で定義されたルーティングヘルパーが正しく委譲されることが保証されています:
def test_url_helper_delegation
@controller = ActionPackAssertionsController.new
@controller.request = ActionDispatch::TestRequest.create
with_routing do |set|
set.draw do
get "/route_one", to: "action_pack_assertions#nothing", as: :route_one
end
assert_equal("/route_one", route_one_path)
end
end
このテストにより、動的に定義されたルーティングヘルパーが method_missing を通じて正しく動作することが検証されています。
まとめ
本PRは、時代遅れになったTODOコメントを解消し、コントローラーテスト専用の機能を適切な場所に配置した変更です。統合テストが独自の実装を持つことを踏まえ、method_missing をコントローラーテストのコンテキストに限定することで、責務の分離を明確にしています。