RSpec Rails:subject+assigns单行写法可行性及失效原因咨询
问题分析与解决方案
为什么你的subject写法会失效?
问题核心在于RSpec的subject不会自动执行——你定义了subject { get :new },但在两个it块里都没有触发这个subject的执行,导致get :new请求压根没运行,assigns[:article]自然是nil,测试必然失败。
而你第一个能正常运行的测试,是因为it块里直接执行了get :new,请求触发后控制器初始化了@article实例,assigns才能拿到对应的值。
修正subject写法的两种方式
方式1:在it块里主动调用subject
如果你坚持要用subject定义请求动作,需要在测试示例里显式触发它:
subject { get :new } it 'creates new instance of Article' do subject # 触发GET请求 expect(assigns[:article]).to be_a(Article) end
方式2:用before钩子替代subject(更推荐)
对于触发请求这类前置动作,RSpec的before钩子语义更清晰,也符合常规测试写法:
before { get :new } it { expect(assigns[:article]).to be_a(Article) } it { expect(assigns(:article)).to be_a(Article) } # 两种assigns写法都能生效
关于「subject与assigns合并为单行」的实现
当然可以!我们可以把subject定义为要断言的目标对象(即assigns[:article]),用before钩子提前触发请求,最后用is_expected简化断言:
before { get :new } subject { assigns[:article] } it { is_expected.to be_a(Article) }
这样就实现了简洁的单行断言写法,语义明确:先执行请求,再断言控制器赋值的article是Article类的实例。
内容的提问来源于stack exchange,提问作者Rigi
相关产品推荐
相关产品推荐

