在view_context中模拟所有Rails路由

问题描述 投票:0回答:1

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。我猜它是一种保护措施,可以防止存在不存在的东西。

ruby-on-rails rspec rails-routing rspec3 presenter
1个回答
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
© www.soinside.com 2019 - 2024. All rights reserved.