控制器中通过helper_method定义的方法在RSpec辅助测试中无法存根
Rails Helper测试存根Controller helper_method失败问题
问题描述
在ApplicationController中定义了一个标记为helper_method的私有方法:
class ApplicationController < ActionController::Base helper_method :is_happy? private def is_happy? true end end
在ApplicationHelper中调用该方法实现业务逻辑:
def show_mood_text return 'Happy' if is_happy? 'Sad' end
为测试is_happy?返回true和false的两种场景,编写了如下RSpec测试代码:
it 'returns Sad when is sad' do allow(helper).to receive(:is_happy?).and_return(false) expect(helper.show_mood_text).to eq "Sad" end
运行测试时触发错误:
Failure/Error: allow(helper).to receive(:is_happy?).and_return(false) #<ActionView::Base:0x00000000009e70> does not implement: is_happy?
原因分析
helper_method的作用是将Controller中的方法暴露给视图上下文,但在RSpec的helper测试环境中,helper对象是ActionView::Base的实例——默认情况下,它不会自动混入Controller中通过helper_method声明的方法,这些方法只有在完整的视图渲染流程中才会被注入到视图上下文里。
解决方案
方案一:关联Controller实例并存根其方法
先创建ApplicationController实例,存根它的is_happy?方法,再将该实例绑定到helper对象的controller属性上,模拟真实运行时的上下文:
it 'returns Sad when is sad' do controller = ApplicationController.new allow(controller).to receive(:is_happy?).and_return(false) helper.controller = controller expect(helper.show_mood_text).to eq "Sad" end
方案二:直接给helper对象添加方法存根
通过define_singleton_method给helper实例直接添加is_happy?方法,或者强制允许RSpec存根未定义的方法:
# 方式1:直接定义单例方法 it 'returns Sad when is sad' do helper.define_singleton_method(:is_happy?) { false } expect(helper.show_mood_text).to eq "Sad" end # 方式2:强制允许存根未定义方法(不推荐,仅作备选) it 'returns Sad when is sad' do allow(helper).to receive(:is_happy?).and_return(false) expect(helper.show_mood_text).to eq "Sad" end
推荐方案一,因为它更贴近Rails实际运行时的上下文逻辑,测试结果更可靠。
内容的提问来源于stack exchange,提问作者WeezHard
相关产品推荐
相关产品推荐

