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_context
(ActionView::Base
)甚至根本没有实现:some_custom_path
,所以会引发错误。我猜这是一种防止存根不存在的东西的保护措施。
答案 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