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
。我猜它是一种保护措施,可以防止存在不存在的东西。
你为什么要模仿所有路径?
我假设你有兴趣实际模拟这些调用,而不仅仅是存根。看到差异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