在view_context中模拟所有Rails路线

时间:2019-03-13 17:43:07

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

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

是否有一种简便的方法可以以编程方式一次模拟所有路径?

我想我可以遍历路径列表(不确定如何做)并逐个模拟每个路径,但是感觉不正确。

谢谢!

编辑:实际上以上代码段甚至都不正确。因为view_contextActionView::Base)甚至根本没有实现:some_custom_path,所以会引发错误。我猜这是一种防止存根不存在的东西的保护措施。

1 个答案:

答案 0 :(得分:1)

为什么要模拟所有路径?

我假设您对实际上感兴趣,并模拟了这些调用,而不仅仅是将其存根。请查看区别here

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

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

我将按照以下方式编写您的测试:

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