【问题标题】:How to set locale default_url_options for functional tests (Rails)如何为功能测试设置语言环境 default_url_options (Rails)
【发布时间】:2009-12-31 22:38:14
【问题描述】:

在我的 application_controller 中,我设置了以下设置以包含 url_for 生成的所有路径的语言环境:

  def default_url_options(options={})
    { :locale => I18n.locale }
  end

然后我的资源路由有一个 :path_prefix = "/:locale"

在网站上运行良好。

但是当涉及到我的功能测试时,:locale 没有与生成的 url 一起传递,因此它们都失败了。我可以通过在我的测试中将语言环境添加到 url 来解决它,如下所示:

  get :new, :locale => 'en'

但我不想手动将语言环境添加到每个功能测试中。

我尝试将上面的default_url_options def添加到test_helper,但似乎没有效果。

有什么方法可以更改 default_url_options 以包含所有测试的语言环境?

谢谢。

【问题讨论】:

    标签: ruby-on-rails testing internationalization


    【解决方案1】:

    对于 Rails 5,我找到了这个简单的解决方案 在test_helper.rb基于action_dispatch/testing/integration.rb

    module ActionDispatch::Integration
      class Session
        def default_url_options
          { locale: I18n.locale }
        end
      end
    end
    

    【讨论】:

    • 感谢您的回答,它对我有用。虽然我想知道是否有任何方法可以使用 ApplicationController 中的自定义 default_url_options,因为编写两次相同的配置没有任何意义。
    • 我只想添加比使用ApplicationController 中定义的选项更好,以保持一致性:ApplicationController.new.send(:default_url_options)
    【解决方案2】:

    在 Rails 3.1-stable 分支中,process method 现在位于 Behavior 模块中。所以这是对我有用的代码(与 John Duff 的回答略有不同):

    class ActionController::TestCase
    
      module Behavior
        def process_with_default_locale(action, parameters = nil, session = nil, flash = nil, http_method = 'GET')
          parameters = { :locale => I18n.default_locale }.merge( parameters || {} )
          process_without_default_locale(action, parameters, session, flash, http_method)
        end 
        alias_method_chain :process, :default_locale
      end 
    end
    

    并且我确保在运行规范/测试之前调用此代码。放置它的好地方是 test_helper 类。

    【讨论】:

    • Martin Carel 在ruby-forum.com/topic/3448797 上列出了这种方法,他还添加了另一种方法:module ActionDispatch::Assertions::RoutingAssertions def assert_recognizes_with_default_locale(expected_options, path, extras={}, message=nil) expected_options = { :locale => I18n.default_locale.to_s }.merge(expected_options || {} ) assert_recognizes_without_default_locale(expected_options, path, extras, message) end alias_method_chain :assert_recognizes, :default_locale end
    • 我还说过修改assert_recognizes方法是作弊。事实上,我认为像这样破解你的测试工具并不是一个好主意,而不是模拟你试图测试的代码(就像在Behavior 模块中添加一个方法一样)。跨度>
    【解决方案3】:

    如果有人在 Rails 4.0 中使用它,process 方法中的参数顺序已经改变,所以你需要使用这个更新的补丁(基于@martin-carel 的回答,只需使用@987654323 @ 参数移到第二个参数):

    class ActionController::TestCase
      module Behavior
        def process_with_default_locale(action, http_method = 'GET', parameters = nil, session = nil, flash = nil)
          parameters = { :locale => I18n.locale }.merge( parameters || {} ) unless I18n.locale.nil?
          process_without_default_locale(action, http_method, parameters, session, flash)
        end
        alias_method_chain :process, :default_locale
      end
    end
    

    希望能帮助解决这个问题的人。

    【讨论】:

      【解决方案4】:

      我尝试了很多例子,但只有这个对我有帮助。它简洁明了。将这段代码 sn -p 添加到 test.rb 中:

      Rails.application.configure do
        # ... other config ...
      
        routes.default_url_options[:locale] = :en
      end
      

      在 Rails 5.1.4 上工作

      【讨论】:

      • 可以确认这也适用于 Rails 6.0.0。
      • 在 Rails 6 中也适用于我,我将它放入 test_helper.rbActiveSupport::TestCase 类中。
      【解决方案5】:

      查看控制器测试用例如何生成 url,似乎没有直接的方法让它使用 defualt_url_options。实际创建 url 的主要块(在测试中)看起来像这样(http://github.com/rails/rails/blob/master/actionpack/lib/action_controller/test_case.rb):

      private
        def build_request_uri(action, parameters)
          unless @request.env['REQUEST_URI']
            options = @controller.__send__(:rewrite_options, parameters)
            options.update(:only_path => true, :action => action)
      
            url = ActionController::UrlRewriter.new(@request, parameters)
            @request.request_uri = url.rewrite(options)
          end
        end
      

      这由流程方法调用,而流程方法又由 get、post、head 或 put 方法调用。获得您正在寻找的东西的一种方法可能是 alias_chain 过程方法。

      class ActionController::TestCase
        def process_with_default_locale(action, parameters = nil, session = nil, flash = nil, http_method = 'GET')
          parameters = {:locale=>'en'}.merge(parameters||{})
          process_without_default_locale(action, parameters, session, flash, http_method)
        end
        alias_method_chain :process, :default_locale
      end
      

      你会想把它放到你的测试助手中,我认为是在 TestCase 类之外。让我知道它是如何为你工作的,我还没有真正测试过,所以我们拭目以待。

      【讨论】:

      • 谢谢,约翰。这解决了上面的具体情况,似乎效果很好!它似乎没有解决的是 TestCase 如何解释命名路由,无论它们是在测试本身中,还是在应用程序中使用。例如,如果我在测试中:redirect_to homepage_url 和 homepath_url 需要语言环境(map.homepage '/:locale', :controller => 'home'),我在运行测试时收到错误,即 url 要求不满意(缺少“语言环境”)。同样,应用程序运行良好,因为 default_url_options 负责添加区域设置。有什么办法解决吗?
      • 让我补充一点,如果这只是测试本身的一个问题,它不会那么糟糕。每当在测试中使用命名路由时,我都可以添加语言环境。但问题是,每当在我的应用程序中使用命名路由时,它也会生成错误(我不想每次都更改所有内容或指定区域设置,以便我的测试运行)。
      • 啊,我没有意识到它也发生在你的应用程序中。我刚遇到一张灯塔票,可能会对您有所帮助(似乎仍然是一个问题,但有一些解决方法)rails.lighthouseapp.com/projects/8994/tickets/…
      • 除此之外,这超出了我的范围,可能值得再问一个关于命名路由和 default_url_options 在应用程序中不起作用的问题,看看是否有人有任何想法。
      【解决方案6】:

      alias_method_chaindeprecated in Rails 5,看来Behavior处理方式变了。

      这是我对上面 Martin Carel 答案的修改,适用于 Rails 5。

      RSpec.configure do |config|
        module ActionController
          class TestCase
            module Behavior
              module LocaleParameter
                def process(action, parameters = {params: {}})
                  unless I18n.locale.nil?
                    parameters[:params][:locale] = I18n.locale
                  end
      
                  super(action, parameters)
                end
              end
      
              prepend Behavior::LocaleParameter
      
            end
          end
        end
      end
      

      我绝不是 Rails 或 Ruby 方面的专家,所以如果这个答案有什么可以改进的地方,请告诉我,我会改变它。

      【讨论】:

      • 是的!这是解决方案,并且添加到每个测试我想定义一个不同的语言环境before :context do I18n.locale = :ca end 我可以测试每个环境我需要的任何语言环境。使用 rails 5.1.4.rc1
      • 我在unless I18n.locale.nil?....之前添加了if parameters[:params].nil? parameters[:params]={} end以避免无参数请求崩溃
      【解决方案7】:

      我在黄瓜测试失败时遇到了这个问题。 我在 url 中使用语言环境作为参数,即http://mysite.com/home?locale=he

      为了解决这个问题,我在测试期间通过根据我使用的环境定义 default_url_options 从 url 中删除所有与语言环境相关的内容:

        # app/controllers/application_controller.rb
        def default_url_options(options={})
          logger.debug "default_url_options is passed options: #{options.inspect}\n"
          ENV["RAILS_ENV"] != "cucumber" ? { :locale => I18n.locale } : {}
        end
      

      【讨论】:

      • 我不确定这是否会暴露某些极端情况,但对我来说这似乎是一个优雅的解决方案。
      【解决方案8】:

      我想出了一个侵入性较小的解决方案来解决这个问题。

      setup :set_default_locale 
      
      def set_default_locale
        def @request.query_parameters
          {:locale => "en"}.merge(@query_parameters)
        end
      end
      

      这种解决方案的优势在于它意味着您只能将默认的语言环境参数应用于某些测试用例,因此您可以测试例如重定向策略本身。

      【讨论】:

        【解决方案9】:

        Ruby 5.1 再次发生了变化。这对我有用:

        class ActionController::TestCase
          module Behavior
            module LocaleParameter
              def process(action, params: {}, **args)
                # Locale parameter must be a string
                params[:locale] = I18n.locale.to_s
                super(action, params: params, **args)
              end
            end
          end
          prepend Behavior::LocaleParameter
        end
        

        【讨论】:

          【解决方案10】:

          通过集成测试,我发现上面的猴子补丁需要有所不同,这对我有用(Rails 2.3.4):

          class ActionController::Integration::Session
            def url_for_with_default_locale(options)
              options = { :locale => 'en' }.merge(options)
              url_for_without_default_locale(options)
            end
            alias_method_chain :url_for, :default_locale
          end
          

          【讨论】:

            【解决方案11】:

            在处理功能测试时不使用default_url_options,而且似乎没有办法在没有猴子修补的情况下定义默认值 (master branch from October 15th 2021)。

            所以我设法通过覆盖test/test_helper.rb 文件中的ActionController::TestCase#process 方法使其工作,如下所示:

            class ActionController::TestCase
              module DefaultParameters
                def process(action, params: {}, **args)
                  params[:locale] ||= 'en'
                  super(action, params: params, **args)
                end
              end
              prepend DefaultParameters
            end
            

            上述代码适用于 Rails 6.1.4,但可能需要针对早期或未来的 Rails 版本进行一些调整。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2015-08-05
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多