【问题标题】:Mocking all Rails routes in a view_context在 view_context 中模拟所有 Rails 路由
【发布时间】:2019-08-04 12:04:24
【问题描述】:

Rails 控制器和视图提供了一个view_context(通常是一个ActionView::Base 对象),它为生成视图提供了上下文。

一种常见的模式是将模型实例包装在 Presenter 类中,在这种情况下,view_context 通常也作为参数传递,因此 Presenter 可以调用视图方法(例如 I8n.t()、Rails 路径助手等。 .) 根据需要。

在我的 RSpec 测试中,我使用模拟来测试 Presenter 中的 view_context 行为。对于路径助手,我必须单独模拟每条路径:

view_context = ActionView::Base.new
user = UserPresenter.new(FactoryBot.create(:user), view: view_context)

allow(view_context).to receive(:some_custom_path) do |opts|
  some_custom_path(opts)
end

有没有一种简单的方法可以一次以编程方式模拟所有路径?

我想我可以遍历路径列表(不知道该怎么做)并逐个模拟,但感觉不是正确的方法。

谢谢!

编辑:实际上上面的 sn-p 甚至都不正确。它会引发错误,因为 view_context (ActionView::Base) 首先甚至没有实现 :some_custom_path。我猜这是一种防止存根不存在的东西的保护措施。

【问题讨论】:

    标签: ruby-on-rails rspec rails-routing rspec3 presenter


    【解决方案1】:

    为什么要模拟所有路径?

    我假设您有兴趣实际上模拟这些调用,而不仅仅是存根它们。看看区别here

    不同的演示者可能会在他们的view_context 上调用不同的path 方法。 我建议您明确地只模拟您期望在您正在测试的演示者中调用的路径。

    您不需要模拟所有路径,因为它们不会每次都被调用。

    我会这样写你的测试:

    describe UserPresenter do
      subject(:user_presenter) { described_class.new(user, view: view_context)
    
      let(:user) { FactoryBot.create(:user) }
      let(:view_context) { instance_double(ActionView::Base) }
      let(:some_custom_path) { 'some/custom/path' }
    
      before do
        allow(view_context).to receive(:some_custom_path).and_return(some_custom_path)
      end
    
      it 'does something'
    end
    

    关于您看到的错误,是的,instance_double 将保护您免于存根未在接收器上实现的方法。

    我确实不推荐你这样做,但如果你正在寻找的只是一个视图对象,它会默默地吞下对 path 方法的调用,那么你可以创建一个像这样的假视图:

    class FakeView
      private
    
      def view_methods
        ActionView::Base.instance_methods - Object.instance_methods
      end
    
      def method_missing(meth, *params, &block)
        view_methods.include?(meth) ? nil : super
      end
    end
    

    然后在您的测试中使用它,例如:

    describe UserPresenter do
      subject(:user_presenter) { described_class.new(user, view: view_context)
    
      let(:user) { FactoryBot.create(:user) }
      let(:view_context) { FakeView.new }
    
      it 'does something'
    end
    

    【讨论】:

      猜你喜欢
      • 2022-01-20
      • 2012-05-02
      • 1970-01-01
      • 2019-06-18
      • 1970-01-01
      • 2010-09-18
      • 2017-08-22
      • 2018-11-02
      • 1970-01-01
      相关资源
      最近更新 更多