RSpec Helper测试中如何mock方法内部调用的current_page?方法
问题原因解析
RSpec Helper Spec 的上下文运行逻辑
RSpec 针对 Rails Helper 类型的测试,会自动做两个混入操作:
- 将待测试的 Helper 模块混入当前测试用例实例(也就是代码中的
self) - 同时提供一个名为
helper的代理对象,该对象也混入了待测试的 Helper 模块
你调用 Helper 方法的方式,直接决定了方法执行时的接收者,以及内部方法调用的查找路径:
- 如果你直接写
do_something(param1, param2)调用,接收者就是self,方法内部调用的current_page?也会默认发送给self - 如果你写
helper.do_something(param1, param2)调用,接收者就是helper代理对象,方法内部的current_page?也会发送给helper对象
报错及修复的原因
你之前写 allow(helper).to receive(:current_page?).and_return(true) 却报错,是因为你调用 do_something 时没有加 helper. 前缀,方法内部的 current_page? 实际是发给 self 的,你 mock helper 对象的方法完全不生效,程序会走 current_page? 的原生实现,原生实现依赖 Request 对象,测试环境没有注入对应 Request 就会抛出你遇到的错误。
而改为 mock self 后,方法内部调用的 current_page? 正好命中了你写的 mock 逻辑,不会走依赖 Request 的原生实现,自然可以正常运行。
你的三个问题明确解答
- 为什么 mock
self可以正常运行?
因为你调用 Helper 方法时的接收者是self,方法内部的current_page?调用默认以self为接收者,mock 逻辑命中,跳过了需要 Request 依赖的原生实现。 - 当前测试场景中的
self是否为 Helper Spec 的类实例?
是的,self就是当前正在运行的 RSpec 测试用例实例,待测试的 Helper 模块已经被 RSpec 自动混入该实例,所以你可以直接调用 Helper 内定义的所有方法。 - 为何无法通过显式指定
helper对象来 mock 内部调用的current_page?方法?
不是无法 mock,是你调用 Helper 方法的接收者不是helper对象,mock 自然不会命中。如果你调整测试代码为通过helper.do_something调用方法,那么 mockhelper对象的current_page?就会正常生效。
两种正确的测试写法参考
写法1:直接调用 Helper 方法,mock self
allow(self).to receive(:current_page?).and_return(true) expect(do_something(param1, param2)).to eq("hello")
写法2:通过 helper 代理调用,mock helper 对象
allow(helper).to receive(:current_page?).and_return(true) expect(helper.do_something(param1, param2)).to eq("hello")
内容的提问来源于stack exchange,提问作者AdamA
相关产品推荐
相关产品推荐

