如何在ActionDispatch::IntegrationTest中使用default_url_options及path_params?
让IntegrationTest调用default_url_options并使用path_params的方法
你遇到的问题是因为默认情况下,IntegrationTest中的路由辅助方法(比如post_url)会使用全局路由上下文(Rails.application.routes)生成URL,不会自动调用测试类实例的default_url_options方法。要解决这个问题,你需要让路由辅助方法使用测试实例的上下文,具体有两种可行方案:
方案一:集成ActionDispatch::Routing::UrlFor模块
在测试类中集成ActionDispatch::Routing::UrlFor模块,并指定路由为应用路由,这样路由辅助方法会使用测试实例的default_url_options:
class BlogControllerTest < ActionDispatch::IntegrationTest # 引入UrlFor模块,让路由辅助方法使用实例上下文 include ActionDispatch::Routing::UrlFor setup do @blog = blogs(:with_posts).first @post = @blog.posts.first # 指定使用应用的路由规则 self.routes = Rails.application.routes end test "accessing a post with default_url_options" do get post_url(@post) assert_response :success end # 该测试可以保留,作为对比 test "accessing a post" do get post_url(@post, blog_id: @blog.id) assert_response :success end private def default_url_options(options = {}) # 合并父类的默认选项,避免覆盖必要配置 super.merge(path_params: { blog_id: @blog.id }) end end
方案二:临时修改全局路由的默认选项
如果不想引入额外模块,可以在setup中临时修改全局路由的default_url_options,并在teardown中恢复原值,避免影响其他测试:
class BlogControllerTest < ActionDispatch::IntegrationTest setup do @blog = blogs(:with_posts).first @post = @blog.posts.first # 保存原始默认选项,用于测试后恢复 @original_defaults = Rails.application.routes.default_url_options.dup # 设置全局路由的path_params默认值 Rails.application.routes.default_url_options[:path_params] = { blog_id: @blog.id } end teardown do # 恢复原始默认选项,避免污染其他测试 Rails.application.routes.default_url_options = @original_defaults end test "accessing a post with default_url_options" do get post_url(@post) assert_response :success end test "accessing a post" do get post_url(@post, blog_id: @blog.id) assert_response :success end end
说明
方案一更符合测试实例的隔离性,每个测试实例可以有自己的default_url_options配置;方案二更简洁,但需要注意全局状态的恢复,避免影响其他测试用例。两种方案都能让url_for自动使用path_params中的blog_id,无需手动在路由辅助方法中传递参数。
内容的提问来源于stack exchange,提问作者Tom Rossi
相关产品推荐
相关产品推荐

